xref: /netbsd/sys/arch/newsmips/newsmips/machdep.c (revision bf9ec67e)
1 /*	$NetBSD: machdep.c,v 1.61 2002/03/05 16:13:57 simonb Exp $	*/
2 
3 /*
4  * Copyright (c) 1988 University of Utah.
5  * Copyright (c) 1992, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * the Systems Programming Group of the University of Utah Computer
10  * Science Department, The Mach Operating System project at
11  * Carnegie-Mellon University and Ralph Campbell.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *	This product includes software developed by the University of
24  *	California, Berkeley and its contributors.
25  * 4. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  *	@(#)machdep.c	8.3 (Berkeley) 1/12/94
42  */
43 
44 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
45 
46 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.61 2002/03/05 16:13:57 simonb Exp $");
47 
48 /* from: Utah Hdr: machdep.c 1.63 91/04/24 */
49 
50 #include "fs_mfs.h"
51 #include "opt_ddb.h"
52 #include "opt_execfmt.h"
53 
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/signalvar.h>
57 #include <sys/kernel.h>
58 #include <sys/map.h>
59 #include <sys/proc.h>
60 #include <sys/buf.h>
61 #include <sys/reboot.h>
62 #include <sys/conf.h>
63 #include <sys/file.h>
64 #include <sys/malloc.h>
65 #include <sys/mbuf.h>
66 #include <sys/msgbuf.h>
67 #include <sys/ioctl.h>
68 #include <sys/device.h>
69 #include <sys/user.h>
70 #include <sys/exec.h>
71 #include <sys/mount.h>
72 #include <sys/syscallargs.h>
73 #include <sys/kcore.h>
74 
75 #include <uvm/uvm_extern.h>
76 #include <sys/sysctl.h>
77 
78 #include <ufs/mfs/mfs_extern.h>		/* mfs_initminiroot() */
79 
80 #include <machine/cpu.h>
81 #include <machine/reg.h>
82 #include <machine/psl.h>
83 #include <machine/pte.h>
84 #include <machine/autoconf.h>
85 #include <machine/bootinfo.h>
86 #include <machine/apbus.h>
87 #include <machine/apcall.h>
88 
89 #include <mips/cache.h>
90 #include <mips/locore.h>
91 
92 #define	_NEWSMIPS_BUS_DMA_PRIVATE
93 #include <machine/bus.h>
94 
95 #ifdef DDB
96 #include <machine/db_machdep.h>
97 #include <ddb/db_access.h>
98 #include <ddb/db_extern.h>
99 #include <ddb/db_sym.h>
100 #endif
101 
102 #include <machine/adrsmap.h>
103 #include <machine/machConst.h>
104 #include <machine/intr.h>
105 #include <newsmips/newsmips/clockreg.h>
106 #include <newsmips/newsmips/machid.h>
107 #include <dev/cons.h>
108 
109 /* the following is used externally (sysctl_hw) */
110 char machine[] = MACHINE;	/* from <machine/param.h> */
111 char machine_arch[] = MACHINE_ARCH;
112 char cpu_model[30];
113 
114 /* Our exported CPU info; we can have only one. */
115 struct cpu_info cpu_info_store;
116 
117 /* maps for VM objects */
118 
119 struct vm_map *exec_map = NULL;
120 struct vm_map *mb_map = NULL;
121 struct vm_map *phys_map = NULL;
122 
123 char *bootinfo = NULL;		/* pointer to bootinfo structure */
124 int physmem;			/* max supported memory, changes to actual */
125 int systype;			/* what type of NEWS we are */
126 struct apbus_sysinfo *_sip = NULL;
127 
128 phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
129 int mem_cluster_cnt;
130 
131 struct idrom idrom;
132 void (*enable_intr) __P((void));
133 void (*disable_intr) __P((void));
134 void (*readmicrotime) __P((struct timeval *tvp));
135 
136 /* System type dependent initializations. */
137 extern void news3400_init __P((void));
138 extern void news5000_init __P((void));
139 
140 static void (*hardware_intr) __P((u_int, u_int, u_int, u_int));
141 u_int ssir;
142 
143 /*
144  *  Local functions.
145  */
146 
147 /* initialize bss, etc. from kernel start, before main() is called. */
148 void mach_init __P((int, int, int, int));
149 
150 void prom_halt __P((int)) __attribute__((__noreturn__));
151 void to_monitor __P((int)) __attribute__((__noreturn__));
152 
153 #ifdef DEBUG
154 /* stacktrace code violates prototypes to get callee's registers */
155 extern void stacktrace __P((void)); /*XXX*/
156 #endif
157 
158 /*
159  * safepri is a safe priority for sleep to set for a spin-wait
160  * during autoconfiguration or after a panic.  Used as an argument to splx().
161  * XXX disables interrupt 5 to disable mips3 on-chip clock, which also
162  * disables mips1 FPU interrupts.
163  */
164 int safepri = MIPS3_PSL_LOWIPL;		/* XXX */
165 
166 extern struct user *proc0paddr;
167 extern u_long bootdev;
168 extern char edata[], end[];
169 
170 /*
171  * Do all the stuff that locore normally does before calling main().
172  * Process arguments passed to us by the prom monitor.
173  * Return the first page address following the system.
174  */
175 void
176 mach_init(x_boothowto, x_bootdev, x_bootname, x_maxmem)
177 	int x_boothowto;
178 	int x_bootdev;
179 	int x_bootname;
180 	int x_maxmem;
181 {
182 	u_long first, last;
183 	caddr_t kernend, v;
184 	vsize_t size;
185 	struct btinfo_magic *bi_magic;
186 	struct btinfo_bootarg *bi_arg;
187 	struct btinfo_systype *bi_systype;
188 #ifdef DDB
189 	struct btinfo_symtab *bi_sym;
190 	int nsym = 0;
191 	char *ssym, *esym;
192 #endif
193 
194 	/* clear the BSS segment */
195 	bzero(edata, end - edata);
196 
197 	systype = NEWS3400;			/* XXX compatibility */
198 
199 	bootinfo = (void *)BOOTINFO_ADDR;	/* XXX */
200 	bi_magic = lookup_bootinfo(BTINFO_MAGIC);
201 	if (bi_magic && bi_magic->magic == BOOTINFO_MAGIC) {
202 		bi_arg = lookup_bootinfo(BTINFO_BOOTARG);
203 		if (bi_arg) {
204 			x_boothowto = bi_arg->howto;
205 			x_bootdev = bi_arg->bootdev;
206 			x_maxmem = bi_arg->maxmem;
207 		}
208 #ifdef DDB
209 		bi_sym = lookup_bootinfo(BTINFO_SYMTAB);
210 		if (bi_sym) {
211 			nsym = bi_sym->nsym;
212 			ssym = (void *)bi_sym->ssym;
213 			esym = (void *)bi_sym->esym;
214 		}
215 #endif
216 
217 		bi_systype = lookup_bootinfo(BTINFO_SYSTYPE);
218 		if (bi_systype)
219 			systype = bi_systype->type;
220 	}
221 
222 #ifdef news5000
223 	if (systype == NEWS5000) {
224 		int i;
225 		char *bootspec = (char *)x_bootdev;
226 
227 		_sip = (void *)bi_arg->sip;
228 		x_maxmem = _sip->apbsi_memsize;
229 		x_maxmem -= 0x00100000;	/* reserve 1MB for ROM monitor */
230 		if (strncmp(bootspec, "scsi", 4) == 0) {
231 			x_bootdev = (5 << 28) | 0;	 /* magic, sd */
232 			bootspec += 4;
233 			if (*bootspec != '(' /*)*/)
234 				goto bootspec_end;
235 			i = strtoul(bootspec + 1, &bootspec, 10);
236 			x_bootdev |= (i << 24);		/* bus */
237 			if (*bootspec != ',')
238 				goto bootspec_end;
239 			i = strtoul(bootspec + 1, &bootspec, 10);
240 			x_bootdev |= (i / 10) << 20;	/* controller */
241 			x_bootdev |= (i % 10) << 16;	/* unit */
242 			if (*bootspec != ',')
243 				goto bootspec_end;
244 			i = strtoul(bootspec + 1, &bootspec, 10);
245 			x_bootdev |= (i << 8);		/* partition */
246 		}
247   bootspec_end:
248 		consinit();
249 	}
250 #endif
251 
252 	/*
253 	 * Save parameters into kernel work area.
254 	 */
255 	*(int *)(MIPS_PHYS_TO_KSEG1(MACH_MAXMEMSIZE_ADDR)) = x_maxmem;
256 	*(int *)(MIPS_PHYS_TO_KSEG1(MACH_BOOTDEV_ADDR)) = x_bootdev;
257 	*(int *)(MIPS_PHYS_TO_KSEG1(MACH_BOOTSW_ADDR)) = x_boothowto;
258 
259 	kernend = (caddr_t)mips_round_page(end);
260 #ifdef DDB
261 	if (nsym)
262 		kernend = (caddr_t)mips_round_page(esym);
263 #endif
264 
265 	/*
266 	 * Set the VM page size.
267 	 */
268 	uvm_setpagesize();
269 
270 	boothowto = x_boothowto;
271 	bootdev = x_bootdev;
272 	physmem = btoc(x_maxmem);
273 
274 	/*
275 	 * Now that we know how much memory we have, initialize the
276 	 * mem cluster array.
277 	 */
278 	mem_clusters[0].start = 0;		/* XXX is this correct? */
279 	mem_clusters[0].size  = ctob(physmem);
280 	mem_cluster_cnt = 1;
281 
282 	/*
283 	 * Copy exception-dispatch code down to exception vector.
284 	 * Initialize locore-function vector.
285 	 * Clear out the I and D caches.
286 	 */
287 	mips_vector_init();
288 
289 	/*
290 	 * We know the CPU type now.  Initialize our DMA tags (might
291 	 * need this early).
292 	 */
293 	newsmips_bus_dma_init();
294 
295 #if 0
296 	if (systype == NEWS5000) {
297 		mips_L2CacheSize = 1024 * 1024;		/* XXX to be safe */
298 		mips3_FlushCache();
299 	}
300 #endif
301 
302 #ifdef DDB
303 	if (nsym)
304 		ddb_init(esym - ssym, ssym, esym);
305 #endif
306 
307 #ifdef KADB
308 	boothowto |= RB_KDB;
309 #endif
310 
311 #ifdef MFS
312 	/*
313 	 * Check to see if a mini-root was loaded into memory. It resides
314 	 * at the start of the next page just after the end of BSS.
315 	 */
316 	if (boothowto & RB_MINIROOT)
317 		kernend += round_page(mfs_initminiroot(kernend));
318 #endif
319 
320 	/*
321 	 * Load the rest of the available pages into the VM system.
322 	 */
323 	first = round_page(MIPS_KSEG0_TO_PHYS(kernend));
324 	last = mem_clusters[0].start + mem_clusters[0].size;
325 	uvm_page_physload(atop(first), atop(last), atop(first), atop(last),
326 	    VM_FREELIST_DEFAULT);
327 
328 	/*
329 	 * Initialize error message buffer (at end of core).
330 	 */
331 	mips_init_msgbuf();
332 
333 	/*
334 	 * Compute the size of system data structures.  pmap_bootstrap()
335 	 * needs some of this information.
336 	 */
337 	size = (vsize_t)allocsys(NULL, NULL);
338 
339 	/*
340 	 * Initialize the virtual memory system.
341 	 */
342 	pmap_bootstrap();
343 
344 	/*
345 	 * Allocate space for proc0's USPACE.
346 	 */
347 	v = (caddr_t)uvm_pageboot_alloc(USPACE);
348 	proc0.p_addr = proc0paddr = (struct user *)v;
349 	proc0.p_md.md_regs = (struct frame *)(v + USPACE) - 1;
350 	curpcb = &proc0.p_addr->u_pcb;
351 	curpcb->pcb_context[11] = MIPS_INT_MASK | MIPS_SR_INT_IE; /* SR */
352 
353 	/*
354 	 * Allocate space for system data structures.  These data structures
355 	 * are allocated here instead of cpu_startup() because physical
356 	 * memory is directly addressable.  We don't have to map these into
357 	 * virtual address space.
358 	 */
359 	v = (caddr_t)uvm_pageboot_alloc(size);
360 	if ((allocsys(v, NULL) - v) != size)
361 		panic("mach_init: table size inconsistency");
362 
363 	/*
364 	 * Determine what model of computer we are running on.
365 	 */
366 	switch (systype) {
367 #ifdef news3400
368 	case NEWS3400:
369 		news3400_init();
370 		strcpy(cpu_model, idrom.id_machine);
371 		if (strcmp(cpu_model, "news3400") == 0 ||
372 		    strcmp(cpu_model, "news3200") == 0 ||
373 		    strcmp(cpu_model, "news3700") == 0) {
374 			/*
375 			 * Set up interrupt handling and I/O addresses.
376 			 */
377 			hardware_intr = news3400_intr;
378 			cpuspeed = 10;
379 		} else {
380 			printf("kernel not configured for machine %s\n",
381 			    cpu_model);
382 		}
383 		break;
384 #endif
385 
386 #ifdef news5000
387 	case NEWS5000:
388 		news5000_init();
389 		strcpy(cpu_model, idrom.id_machine);
390 		if (strcmp(cpu_model, "news5000") == 0 ||
391 		    strcmp(cpu_model, "news5900") == 0) {
392 			/*
393 			 * Set up interrupt handling and I/O addresses.
394 			 */
395 			hardware_intr = news5000_intr;
396 			cpuspeed = 50;	/* ??? XXX */
397 		} else {
398 			printf("kernel not configured for machine %s\n",
399 			    cpu_model);
400 		}
401 		break;
402 #endif
403 
404 	default:
405 		printf("kernel not configured for systype %d\n", systype);
406 		break;
407 	}
408 }
409 
410 void
411 mips_machdep_cache_config(void)
412 {
413 	/* All r4k news boxen have a 1MB L2 cache. */
414 	if (CPUISMIPS3)
415 		mips_sdcache_size = 1024 * 1024;
416 }
417 
418 /*
419  * cpu_startup: allocate memory for variable-sized tables,
420  * initialize cpu, and do autoconfiguration.
421  */
422 void
423 cpu_startup()
424 {
425 	register unsigned i;
426 	int base, residual;
427 	vaddr_t minaddr, maxaddr;
428 	vsize_t size;
429 	char pbuf[9];
430 #ifdef DEBUG
431 	extern int pmapdebug;
432 	int opmapdebug = pmapdebug;
433 
434 	pmapdebug = 0;
435 #endif
436 
437 	/*
438 	 * Good {morning,afternoon,evening,night}.
439 	 */
440 	printf(version);
441 	format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
442 	printf("total memory = %s\n", pbuf);
443 
444 	/*
445 	 * Allocate virtual address space for file I/O buffers.
446 	 * Note they are different than the array of headers, 'buf',
447 	 * and usually occupy more virtual memory than physical.
448 	 */
449 	size = MAXBSIZE * nbuf;
450 	if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(size),
451 		    NULL, UVM_UNKNOWN_OFFSET, 0,
452 		    UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE,
453 				UVM_ADV_NORMAL, 0)) != 0)
454 		panic("startup: cannot allocate VM for buffers");
455 	minaddr = (vaddr_t)buffers;
456 	base = bufpages / nbuf;
457 	residual = bufpages % nbuf;
458 	for (i = 0; i < nbuf; i++) {
459 		vsize_t curbufsize;
460 		vaddr_t curbuf;
461 		struct vm_page *pg;
462 
463 		/*
464 		 * Each buffer has MAXBSIZE bytes of VM space allocated.  Of
465 		 * that MAXBSIZE space, we allocate and map (base+1) pages
466 		 * for the first "residual" buffers, and then we allocate
467 		 * "base" pages for the rest.
468 		 */
469 		curbuf = (vaddr_t) buffers + (i * MAXBSIZE);
470 		curbufsize = NBPG * ((i < residual) ? (base+1) : base);
471 
472 		while (curbufsize) {
473 			pg = uvm_pagealloc(NULL, 0, NULL, 0);
474 			if (pg == NULL)
475 				panic("cpu_startup: not enough memory for "
476 				    "buffer cache");
477 			pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg),
478 				       VM_PROT_READ|VM_PROT_WRITE);
479 			curbuf += PAGE_SIZE;
480 			curbufsize -= PAGE_SIZE;
481 		}
482 	}
483 	pmap_update(pmap_kernel());
484 
485 	/*
486 	 * Allocate a submap for exec arguments.  This map effectively
487 	 * limits the number of processes exec'ing at any time.
488 	 */
489 	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
490 				   16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
491 	/*
492 	 * Allocate a submap for physio
493 	 */
494 	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
495 				   VM_PHYS_SIZE, 0, FALSE, NULL);
496 
497 	/*
498 	 * No need to allocate an mbuf cluster submap.  Mbuf clusters
499 	 * are allocated via the pool allocator, and we use KSEG to
500 	 * map those pages.
501 	 */
502 
503 #ifdef DEBUG
504 	pmapdebug = opmapdebug;
505 #endif
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 buffers, so they can be used to read disk labels.
513 	 */
514 	bufinit();
515 }
516 
517 
518 /*
519  * machine dependent system variables.
520  */
521 int
522 cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
523 	int *name;
524 	u_int namelen;
525 	void *oldp;
526 	size_t *oldlenp;
527 	void *newp;
528 	size_t newlen;
529 	struct proc *p;
530 {
531 	/* all sysctl names at this level are terminal */
532 	if (namelen != 1)
533 		return (ENOTDIR);		/* overloaded */
534 
535 	switch (name[0]) {
536 
537 	default:
538 		return (EOPNOTSUPP);
539 	}
540 	/* NOTREACHED */
541 }
542 
543 /*
544  * lookup_bootinfo:
545  * Look up information in bootinfo of boot loader.
546  */
547 void *
548 lookup_bootinfo(type)
549 	int type;
550 {
551 	struct btinfo_common *bt;
552 	char *help = bootinfo;
553 
554 	/* Check for a bootinfo record first. */
555 	if (help == NULL)
556 		return (NULL);
557 
558 	do {
559 		bt = (struct btinfo_common *)help;
560 		if (bt->type == type)
561 			return ((void *)help);
562 		help += bt->next;
563 	} while (bt->next != 0 &&
564 		(size_t)help < (size_t)bootinfo + BOOTINFO_SIZE);
565 
566 	return (NULL);
567 }
568 
569 /*
570  * call PROM to halt or reboot.
571  */
572 void
573 prom_halt(howto)
574 	int howto;
575 
576 {
577 #ifdef news5000
578 	if (systype == NEWS5000)
579 		apcall_exit(howto);
580 #endif
581 #ifdef news3400
582 	if (systype == NEWS3400)
583 		to_monitor(howto);
584 #endif
585 	for (;;);
586 }
587 
588 int	waittime = -1;
589 
590 void
591 cpu_reboot(howto, bootstr)
592 	volatile int howto;
593 	char *bootstr;
594 {
595 
596 	/* take a snap shot before clobbering any registers */
597 	if (curproc)
598 		savectx((struct user *)curpcb);
599 
600 #ifdef DEBUG
601 	if (panicstr)
602 		stacktrace();
603 #endif
604 
605 	/* If system is cold, just halt. */
606 	if (cold) {
607 		howto |= RB_HALT;
608 		goto haltsys;
609 	}
610 
611 	/* If "always halt" was specified as a boot flag, obey. */
612 	if ((boothowto & RB_HALT) != 0)
613 		howto |= RB_HALT;
614 
615 	boothowto = howto;
616 	if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
617 		/*
618 		 * Synchronize the disks....
619 		 */
620 		waittime = 0;
621 		vfs_shutdown();
622 
623 		/*
624 		 * If we've been adjusting the clock, the todr
625 		 * will be out of synch; adjust it now.
626 		 */
627 		resettodr();
628 	}
629 
630 	/* Disable interrupts. */
631 	disable_intr();
632 
633 	splhigh();
634 
635 	/* If rebooting and a dump is requested do it. */
636 #if 0
637 	if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
638 #else
639 	if (howto & RB_DUMP)
640 #endif
641 		dumpsys();
642 
643 haltsys:
644 
645 	/* run any shutdown hooks */
646 	doshutdownhooks();
647 
648 	if ((howto & RB_POWERDOWN) == RB_POWERDOWN)
649 		prom_halt(0x80);	/* rom monitor RB_PWOFF */
650 
651 	/* Finally, halt/reboot the system. */
652 	printf("%s\n\n", howto & RB_HALT ? "halted." : "rebooting...");
653 	prom_halt(howto & RB_HALT);
654 	/*NOTREACHED*/
655 }
656 
657 /*
658  * Return the best possible estimate of the time in the timeval
659  * to which tvp points.  Unfortunately, we can't read the hardware registers.
660  * We guarantee that the time will be greater than the value obtained by a
661  * previous call.
662  */
663 void
664 microtime(tvp)
665 	register struct timeval *tvp;
666 {
667 	int s = splclock();
668 	static struct timeval lasttime;
669 
670 	if (readmicrotime)
671 		readmicrotime(tvp);
672 	else
673 		*tvp = time;
674 
675 	if (tvp->tv_sec == lasttime.tv_sec &&
676 	    tvp->tv_usec <= lasttime.tv_usec &&
677 	    (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
678 		tvp->tv_sec++;
679 		tvp->tv_usec -= 1000000;
680 	}
681 	lasttime = *tvp;
682 	splx(s);
683 }
684 
685 void
686 delay(n)
687 	int n;
688 {
689 	DELAY(n);
690 }
691 
692 #include "zsc.h"
693 
694 int zssoft __P((void));
695 
696 void
697 cpu_intr(status, cause, pc, ipending)
698 	u_int32_t status;
699 	u_int32_t cause;
700 	u_int32_t pc;
701 	u_int32_t ipending;
702 {
703 	uvmexp.intrs++;
704 
705 	/* device interrupts */
706 	(*hardware_intr)(status, cause, pc, ipending);
707 
708 	/* software simulated interrupt */
709 	if ((ipending & MIPS_SOFT_INT_MASK_1) ||
710 	    (ssir && (status & MIPS_SOFT_INT_MASK_1))) {
711 
712 #define DO_SIR(bit, fn)						\
713 	do {							\
714 		if (n & (bit)) {				\
715 			uvmexp.softs++;				\
716 			fn;					\
717 		}						\
718 	} while (0)
719 
720 		unsigned n;
721 		n = ssir; ssir = 0;
722 		_clrsoftintr(MIPS_SOFT_INT_MASK_1);
723 
724 #if NZSC > 0
725 		DO_SIR(SIR_SERIAL, zssoft());
726 #endif
727 		DO_SIR(SIR_NET, netintr());
728 #undef DO_SIR
729 	}
730 
731 	/* 'softclock' interrupt */
732 	if (ipending & MIPS_SOFT_INT_MASK_0) {
733 		_clrsoftintr(MIPS_SOFT_INT_MASK_0);
734 		uvmexp.softs++;
735 		intrcnt[SOFTCLOCK_INTR]++;
736 		softclock(NULL);
737 	}
738 }
739