xref: /netbsd/sys/arch/mvmeppc/mvmeppc/machdep.c (revision bf9ec67e)
1 /*	$NetBSD: machdep.c,v 1.3 2002/04/23 12:41:06 kleink Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5  * Copyright (C) 1995, 1996 TooLs GmbH.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "opt_compat_netbsd.h"
35 #include "opt_mvmetype.h"
36 #include "opt_ddb.h"
37 
38 #include <sys/param.h>
39 #include <sys/buf.h>
40 #include <sys/conf.h>
41 #include <sys/device.h>
42 #include <sys/exec.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/map.h>
46 #include <sys/mbuf.h>
47 #include <sys/mount.h>
48 #include <sys/msgbuf.h>
49 #include <sys/proc.h>
50 #include <sys/reboot.h>
51 #include <sys/syscallargs.h>
52 #include <sys/syslog.h>
53 #include <sys/systm.h>
54 #include <sys/user.h>
55 
56 #include <uvm/uvm_extern.h>
57 
58 #include <sys/sysctl.h>
59 
60 #include <net/netisr.h>
61 
62 #include <machine/autoconf.h>
63 #include <machine/bat.h>
64 #include <machine/bootinfo.h>
65 #include <machine/bus.h>
66 #include <machine/intr.h>
67 #include <machine/pmap.h>
68 #include <machine/platform.h>
69 #include <machine/powerpc.h>
70 #include <machine/trap.h>
71 
72 #include <dev/cons.h>
73 
74 #if 0
75 #include "vga.h"
76 #if (NVGA > 0)
77 #include <dev/ic/mc6845reg.h>
78 #include <dev/ic/pcdisplayvar.h>
79 #include <dev/ic/vgareg.h>
80 #include <dev/ic/vgavar.h>
81 #endif
82 
83 #include "pckbc.h"
84 #if (NPCKBC > 0)
85 #include <dev/isa/isareg.h>
86 #include <dev/ic/i8042reg.h>
87 #include <dev/ic/pckbcvar.h>
88 #endif
89 #endif
90 
91 #include "com.h"
92 #if (NCOM > 0)
93 #include <sys/termios.h>
94 #include <dev/ic/comreg.h>
95 #include <dev/ic/comvar.h>
96 void comsoft(void);
97 #endif
98 
99 #ifdef DDB
100 #include <machine/db_machdep.h>
101 #include <ddb/db_extern.h>
102 #endif
103 
104 void initppc(u_long, u_long, void *);
105 void dumpsys(void);
106 void strayintr(int);
107 int lcsplx(int);
108 
109 /* Our exported CPU info; we have only one right now. */
110 struct cpu_info cpu_info_store;
111 
112 /*
113  * Global variables used here and there
114  */
115 struct vm_map *exec_map = NULL;
116 struct vm_map *mb_map = NULL;
117 struct vm_map *phys_map = NULL;
118 
119 struct mvmeppc_bootinfo bootinfo;
120 
121 char machine[] = MACHINE;		/* machine */
122 char machine_arch[] = MACHINE_ARCH;	/* machine architecture */
123 
124 struct pcb *curpcb;
125 struct pmap *curpm;
126 struct proc *fpuproc;
127 
128 extern struct user *proc0paddr;
129 
130 struct bat battable[16];
131 
132 vaddr_t mvmeppc_intr_reg;	/* PReP-compatible  interrupt vector register */
133 
134 struct mem_region physmemr, availmemr;
135 
136 paddr_t msgbuf_paddr;
137 vaddr_t msgbuf_vaddr;
138 
139 paddr_t avail_end;			/* XXX temporary */
140 
141 void install_extint(void (*)(void));
142 
143 
144 void
145 initppc(startkernel, endkernel, btinfo)
146 	u_long startkernel, endkernel;
147 	void *btinfo;
148 {
149 	extern int trapcode, trapsize;
150 	extern int alitrap, alisize;
151 	extern int dsitrap, dsisize;
152 	extern int isitrap, isisize;
153 	extern int decrint, decrsize;
154 	extern int tlbimiss, tlbimsize;
155 	extern int tlbdlmiss, tlbdlmsize;
156 	extern int tlbdsmiss, tlbdsmsize;
157 #ifdef DDB
158 	extern int ddblow, ddbsize;
159 	extern void *startsym, *endsym;
160 #endif
161 	int exc, scratch;
162 
163 	/*
164 	 * Copy bootinfo.
165 	 */
166 	memcpy(&bootinfo, btinfo, sizeof(bootinfo));
167 
168 	/*
169 	 * Figure out the board family/type.
170 	 */
171 	ident_platform();
172 
173 	if (platform == NULL) {
174 		extern void _mvmeppc_unsup_board(const char *, const char *);
175 		char msg[80];
176 
177 		sprintf(msg, "Unsupported model: MVME%04x",
178 		    bootinfo.bi_modelnumber);
179 		_mvmeppc_unsup_board(msg, &msg[strlen(msg)]);
180 		/* NOTREACHED */
181 	}
182 
183 	/*
184 	 * Set memory region
185 	 */
186 	physmemr.start = 0;
187 	physmemr.size = bootinfo.bi_memsize & ~PGOFSET;
188 	availmemr.start = (endkernel + PGOFSET) & ~PGOFSET;
189 	availmemr.size = bootinfo.bi_memsize - availmemr.start;
190 	avail_end = physmemr.start + physmemr.size;    /* XXX temporary */
191 
192 	/*
193 	 * Set CPU clock
194 	 */
195 	{
196 		extern u_long ticks_per_sec, ns_per_tick;
197 
198 		ticks_per_sec = bootinfo.bi_clocktps;
199 		ns_per_tick = 1000000000 / ticks_per_sec;
200 	}
201 
202 	proc0.p_addr = proc0paddr;
203 	memset(proc0.p_addr, 0, sizeof *proc0.p_addr);
204 
205 	curpcb = &proc0paddr->u_pcb;
206 
207 	curpm = curpcb->pcb_pmreal = curpcb->pcb_pm = pmap_kernel();
208 
209 	/*
210 	 * boothowto
211 	 */
212 	boothowto = bootinfo.bi_boothowto;
213 
214 	/*
215 	 * Initialize BAT registers to unmapped to not generate
216 	 * overlapping mappings below.
217 	 */
218 	asm volatile ("mtibatu 0,%0" :: "r"(0));
219 	asm volatile ("mtibatu 1,%0" :: "r"(0));
220 	asm volatile ("mtibatu 2,%0" :: "r"(0));
221 	asm volatile ("mtibatu 3,%0" :: "r"(0));
222 	asm volatile ("mtdbatu 0,%0" :: "r"(0));
223 	asm volatile ("mtdbatu 1,%0" :: "r"(0));
224 	asm volatile ("mtdbatu 2,%0" :: "r"(0));
225 	asm volatile ("mtdbatu 3,%0" :: "r"(0));
226 
227 	/*
228 	 * Set up initial BAT table
229 	 */
230 	/* map the lowest 256 MB area */
231 	battable[0].batl = BATL(0x00000000, BAT_M, BAT_PP_RW);
232 	battable[0].batu = BATU(0x00000000, BAT_BL_256M, BAT_Vs);
233 
234 	/* map the PCI/ISA I/O 256 MB area */
235 	battable[MVMEPPC_PHYS_BASE_IO >> 28].batl =
236 	    BATL(MVMEPPC_PHYS_BASE_IO, BAT_I|BAT_G, BAT_PP_RW);
237 	battable[MVMEPPC_PHYS_BASE_IO >> 28].batu =
238 	    BATU(MVMEPPC_KVA_BASE_IO, BAT_BL_256M, BAT_Vs);
239 
240 	/* map the PCI/ISA MEMORY 256 MB area */
241 	battable[MVMEPPC_PHYS_BASE_MEM >> 28].batl =
242 	    BATL(MVMEPPC_PHYS_BASE_MEM, BAT_I|BAT_G, BAT_PP_RW);
243 	battable[MVMEPPC_PHYS_BASE_MEM >> 28].batu =
244 	    BATU(MVMEPPC_KVA_BASE_MEM, BAT_BL_256M, BAT_Vs);
245 
246 	/*
247 	 * Now setup fixed bat registers
248 	 */
249 	asm volatile ("mtibatl 0,%0; mtibatu 0,%1"
250 		      :: "r"(battable[0].batl), "r"(battable[0].batu));
251 	asm volatile ("mtdbatl 0,%0; mtdbatu 0,%1"
252 		      :: "r"(battable[0].batl), "r"(battable[0].batu));
253 
254 	asm volatile ("mtdbatl 2,%0; mtdbatu 1,%1"
255 	    :: "r"(battable[MVMEPPC_PHYS_BASE_IO >> 28].batl),
256 	       "r"(battable[MVMEPPC_PHYS_BASE_IO >> 28].batu));
257 	asm volatile ("mtdbatl 3,%0; mtdbatu 2,%1"
258 	    :: "r"(battable[MVMEPPC_PHYS_BASE_MEM >> 28].batl),
259 	       "r"(battable[MVMEPPC_PHYS_BASE_MEM >> 28].batu));
260 
261 	asm volatile ("sync; isync");
262 
263 	/*
264 	 * Set up trap vectors
265 	 */
266 	for (exc = EXC_RSVD; exc <= EXC_LAST; exc += 0x100)
267 		switch (exc) {
268 		default:
269 			memcpy((void *)exc, &trapcode, (size_t)&trapsize);
270 			break;
271 		case EXC_EXI:
272 			/*
273 			 * This one is (potentially) installed during autoconf
274 			 */
275 			break;
276 		case EXC_ALI:
277 			memcpy((void *)EXC_ALI, &alitrap, (size_t)&alisize);
278 			break;
279 		case EXC_DSI:
280 			memcpy((void *)EXC_DSI, &dsitrap, (size_t)&dsisize);
281 			break;
282 		case EXC_ISI:
283 			memcpy((void *)EXC_ISI, &isitrap, (size_t)&isisize);
284 			break;
285 		case EXC_DECR:
286 			memcpy((void *)EXC_DECR, &decrint, (size_t)&decrsize);
287 			break;
288 		case EXC_IMISS:
289 			memcpy((void *)EXC_IMISS, &tlbimiss,
290 			    (size_t)&tlbimsize);
291 			break;
292 		case EXC_DLMISS:
293 			memcpy((void *)EXC_DLMISS, &tlbdlmiss,
294 			    (size_t)&tlbdlmsize);
295 			break;
296 		case EXC_DSMISS:
297 			memcpy((void *)EXC_DSMISS, &tlbdsmiss,
298 			    (size_t)&tlbdsmsize);
299 			break;
300 #ifdef DDB
301 		case EXC_PGM:
302 		case EXC_TRC:
303 		case EXC_BPT:
304 			memcpy((void *)exc, &ddblow, (size_t)&ddbsize);
305 			break;
306 #endif
307 		}
308 
309 	__syncicache((void *)EXC_RST, EXC_LAST - EXC_RST + 0x100);
310 
311 #ifdef DEBUG
312 	/*
313 	 * i386 port says, that this shouldn't be here,
314 	 * but I really think the console should be initialized
315 	 * as early as possible.
316 	 */
317 	consinit();
318 #endif
319 
320 	/*
321 	 * external interrupt handler install
322 	 */
323 	install_extint(platform->ext_intr);
324 
325 	/*
326 	 * Now enable translation (and machine checks/recoverable interrupts).
327 	 */
328 	asm volatile ("eieio; mfmsr %0; ori %0,%0,%1; mtmsr %0; isync"
329 		      : "=r"(scratch) : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI));
330 
331         /*
332 	 * Set the page size.
333 	 */
334 	uvm_setpagesize();
335 
336 	/*
337 	 * Initialize pmap module.
338 	 */
339 	pmap_bootstrap(startkernel, endkernel, NULL);
340 
341 #ifdef DDB
342 	ddb_init((int)((u_long)endsym - (u_long)startsym), startsym, endsym);
343 
344 	if (boothowto & RB_KDB)
345 		Debugger();
346 #endif
347 }
348 
349 void
350 mem_regions(mem, avail)
351 	struct mem_region **mem, **avail;
352 {
353 
354 	*mem = &physmemr;
355 	*avail = &availmemr;
356 }
357 
358 void
359 install_extint(handler)
360 	void (*handler)(void);
361 {
362 	extern u_char extint[];
363 	extern u_long extsize;
364 	extern u_long extint_call;
365 	u_long offset = (u_long)handler - (u_long)&extint_call;
366 	int omsr, msr;
367 
368 #ifdef DIAGNOSTIC
369 	if (offset > 0x1ffffff)
370 		panic("install_extint: too far away");
371 #endif
372 	asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1"
373 		      : "=r"(omsr), "=r"(msr) : "K"((u_short)~PSL_EE));
374 	extint_call = (extint_call & 0xfc000003) | offset;
375 	memcpy((void *)EXC_EXI, &extint, (size_t)&extsize);
376 	__syncicache((void *)&extint_call, sizeof extint_call);
377 	__syncicache((void *)EXC_EXI, (int)&extsize);
378 	asm volatile ("mtmsr %0" :: "r"(omsr));
379 }
380 
381 /*
382  * Machine dependent startup code.
383  */
384 void
385 cpu_startup()
386 {
387 	int sz, i;
388 	caddr_t v;
389 	vaddr_t minaddr, maxaddr;
390 	int base, residual;
391 	char pbuf[9];
392 
393 	proc0.p_addr = proc0paddr;
394 	v = (caddr_t)proc0paddr + USPACE;
395 
396 	/*
397 	 * Mapping PReP-compatible interrput vector register.
398 	 */
399 	if (!(mvmeppc_intr_reg = uvm_km_valloc(kernel_map, round_page(NBPG))))
400 		panic("startup: no room for interrupt register");
401 	pmap_enter(pmap_kernel(), mvmeppc_intr_reg, MVMEPPC_INTR_REG,
402 	    VM_PROT_READ|VM_PROT_WRITE, VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED);
403 	pmap_update(pmap_kernel());
404 
405 	/*
406 	 * Initialize error message buffer (at end of core).
407 	 */
408 	if (!(msgbuf_vaddr = uvm_km_alloc(kernel_map, round_page(MSGBUFSIZE))))
409 		panic("startup: no room for message buffer");
410 	for (i = 0; i < btoc(MSGBUFSIZE); i++)
411 		pmap_enter(pmap_kernel(), msgbuf_vaddr + i * NBPG,
412 		    msgbuf_paddr + i * NBPG, VM_PROT_READ|VM_PROT_WRITE,
413 		    VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED);
414 	pmap_update(pmap_kernel());
415 	initmsgbuf((caddr_t)msgbuf_vaddr, round_page(MSGBUFSIZE));
416 
417 	printf("%s", version);
418 
419 	printf("Model: %s\n", platform->model);
420 	printf("Core Speed: %dMHz, Bus Speed: %dMHz\n",
421 		bootinfo.bi_mpuspeed/1000000, bootinfo.bi_busspeed/1000000);
422 
423 	cpu_identify(NULL, 0);
424 
425 	format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
426 	printf("total memory = %s\n", pbuf);
427 
428 	/*
429 	 * Find out how much space we need, allocate it,
430 	 * and then give everything true virtual addresses.
431 	 */
432 	sz = (int)allocsys(NULL, NULL);
433 	if ((v = (caddr_t)uvm_km_zalloc(kernel_map, round_page(sz))) == 0)
434 		panic("startup: no room for tables");
435 	if (allocsys(v, NULL) - v != sz)
436 		panic("startup: table size inconsistency");
437 
438 	/*
439 	 * Now allocate buffers proper.  They are different than the above
440 	 * in that they usually occupy more virtual memory than physical.
441 	 */
442 	sz = MAXBSIZE * nbuf;
443 	if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(sz),
444 		    NULL, UVM_UNKNOWN_OFFSET, 0,
445 		    UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE,
446 				UVM_ADV_NORMAL, 0)) != 0)
447 		panic("startup: cannot allocate VM for buffers");
448 	minaddr = (vaddr_t)buffers;
449 	base = bufpages / nbuf;
450 	residual = bufpages % nbuf;
451 	if (base >= MAXBSIZE) {
452 		/* Don't want to alloc more physical mem than ever needed */
453 		base = MAXBSIZE;
454 		residual = 0;
455 	}
456 	for (i = 0; i < nbuf; i++) {
457 		vsize_t curbufsize;
458 		vaddr_t curbuf;
459 		struct vm_page *pg;
460 
461 		/*
462 		 * Each buffer has MAXBSIZE bytes of VM space allocated.  Of
463 		 * that MAXBSIZE space, we allocate and map (base+1) pages
464 		 * for the first "residual" buffers, and then we allocate
465 		 * "base" pages for the rest.
466 		 */
467 		curbuf = (vaddr_t) buffers + (i * MAXBSIZE);
468 		curbufsize = NBPG * ((i < residual) ? (base+1) : base);
469 
470 		while (curbufsize) {
471 			pg = uvm_pagealloc(NULL, 0, NULL, 0);
472 			if (pg == NULL)
473 				panic("startup: not enough memory for "
474 					"buffer cache");
475 			pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg),
476 			    VM_PROT_READ | VM_PROT_WRITE);
477 			curbuf += PAGE_SIZE;
478 			curbufsize -= PAGE_SIZE;
479 		}
480 	}
481 	pmap_update(kernel_map->pmap);
482 
483 	/*
484 	 * Allocate a submap for exec arguments.  This map effectively
485 	 * limits the number of processes exec'ing at any time.
486 	 */
487 	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
488 				 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
489 
490 	/*
491 	 * Allocate a submap for physio
492 	 */
493 	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
494 				 VM_PHYS_SIZE, 0, FALSE, NULL);
495 
496 #ifndef PMAP_MAP_POOLPAGE
497 	/*
498 	 * We need to allocate an mbuf cluster submap if the pool
499 	 * allocater isn't using direct-mapped pool pages.
500 	 */
501 	mb_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
502 				 nmbclusters * mclbytes, VM_MAP_INTRSAFE,
503 				 FALSE, NULL);
504 #endif
505 
506 	format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free));
507 	printf("avail memory = %s\n", pbuf);
508 	format_bytes(pbuf, sizeof(pbuf), bufpages * NBPG);
509 	printf("using %d buffers containing %s of memory\n", nbuf, pbuf);
510 
511 	/*
512 	 * Set up the buffers.
513 	 */
514 	bufinit();
515 
516 	/*
517 	 * Now allow hardware interrupts.
518 	 */
519 	{
520 		int msr;
521 
522 		splraise(-1);
523 		asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0"
524 			      : "=r"(msr) : "K"(PSL_EE));
525 	}
526 
527 	mvmeppc_bus_space_init();
528 }
529 
530 /*
531  * consinit
532  * Initialize system console.
533  */
534 void
535 consinit()
536 {
537 	static int initted = 0;
538 
539 	if (initted)
540 		return;
541 	initted = 1;
542 
543 #if 0
544 
545 #if (NPFB > 0)
546 	if (!strcmp(consinfo->devname, "fb")) {
547 		pfb_cnattach(consinfo->addr);
548 #if (NPCKBC > 0)
549 		pckbc_cnattach(&mvmeppc_isa_io_space_tag, IO_KBD, KBCMDP,
550 		    PCKBC_KBD_SLOT);
551 #endif
552 		return;
553 	}
554 #endif
555 
556 #if (NVGA > 0) || (NGTEN > 0)
557 	if (!strcmp(consinfo->devname, "vga")) {
558 #if (NGTEN > 0)
559 		if (!gten_cnattach(&mvmeppc_mem_space_tag))
560 			goto dokbd;
561 #endif
562 #if (NVGA > 0)
563 		if (!vga_cnattach(&mvmeppc_io_space_tag, &mvmeppc_mem_space_tag,
564 				-1, 1))
565 			goto dokbd;
566 #endif
567 dokbd:
568 #if (NPCKBC > 0)
569 		pckbc_cnattach(&mvmeppc_isa_io_space_tag, IO_KBD, KBCMDP,
570 		    PCKBC_KBD_SLOT);
571 #endif
572 		return;
573 	}
574 #endif /* PC | VGA */
575 
576 #endif
577 
578 #if (NCOM > 0)
579 	if (!strcmp(bootinfo.bi_consoledev, "PC16550")) {
580 		bus_space_tag_t tag = &mvmeppc_isa_io_bs_tag;
581 		bus_addr_t caddr[2] = {0x3f8, 0x2f8};
582 		int rv;
583 		rv = comcnattach(tag, caddr[bootinfo.bi_consolechan],
584 		    bootinfo.bi_consolespeed, COM_FREQ,
585 		    bootinfo.bi_consolecflag);
586 		if (rv)
587 			panic("can't init serial console");
588 
589 		return;
590 	}
591 #endif
592 	panic("invalid console device %s", bootinfo.bi_consoledev);
593 }
594 
595 void
596 dumpsys()
597 {
598 
599 	printf("dumpsys: TBD\n");
600 }
601 
602 /*
603  * Soft networking interrupts.
604  */
605 void
606 softnet()
607 {
608 	extern volatile int netisr;
609 	int isr;
610 
611 	isr = netisr;
612 	netisr = 0;
613 
614 #define DONETISR(bit, fn) do {	\
615 	if (isr & (1 << bit))	\
616 		fn();		\
617 } while (0)
618 
619 #include <net/netisr_dispatch.h>
620 
621 #undef DONETISR
622 }
623 
624 /*
625  * Soft tty interrupts.
626  */
627 void
628 softserial()
629 {
630 
631 #if (NCOM > 0)
632 	comsoft();
633 #endif
634 }
635 
636 /*
637  * Stray interrupts.
638  */
639 void
640 strayintr(irq)
641 	int irq;
642 {
643 
644 	log(LOG_ERR, "stray interrupt %d\n", irq);
645 }
646 
647 /*
648  * Halt or reboot the machine after syncing/dumping according to howto.
649  */
650 void
651 cpu_reboot(howto, what)
652 	int howto;
653 	char *what;
654 {
655 	static int syncing;
656 
657 	if (cold) {
658 		howto |= RB_HALT;
659 		goto halt_sys;
660 	}
661 
662 	boothowto = howto;
663 	if ((howto & RB_NOSYNC) == 0 && syncing == 0) {
664 		syncing = 1;
665 		vfs_shutdown();		/* sync */
666 		resettodr();		/* set wall clock */
667 	}
668 
669 	/* Disable intr */
670 	splhigh();
671 
672 	/* Do dump if requested */
673 	if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
674 		dumpsys();
675 
676 halt_sys:
677 	doshutdownhooks();
678 
679 	if (howto & RB_HALT) {
680                 printf("\n");
681                 printf("The operating system has halted.\n");
682                 printf("Please press any key to reboot.\n\n");
683                 cnpollc(1);	/* for proper keyboard command handling */
684                 cngetc();
685                 cnpollc(0);
686 	}
687 
688 	printf("rebooting...\n\n");
689 
690 #if 0
691 	(*platform->reset)();
692 #endif
693 
694 	for (;;)
695 		continue;
696 	/* NOTREACHED */
697 }
698 
699 /*
700  * lcsplx() is called from locore; it is an open-coded version of
701  * splx() differing in that it returns the previous priority level.
702  */
703 int
704 lcsplx(ipl)
705 	int ipl;
706 {
707 	int oldcpl;
708 
709 	__asm__ volatile("sync; eieio\n");	/* reorder protect */
710 	oldcpl = cpl;
711 	cpl = ipl;
712 	if (ipending & ~ipl)
713 		do_pending_int();
714 	__asm__ volatile("sync; eieio\n");	/* reorder protect */
715 
716 	return (oldcpl);
717 }
718