From c822c6bd8450405ad61e3293552c7561e7ca34df Mon Sep 17 00:00:00 2001 From: pk Date: Mon, 9 Dec 2002 16:11:50 +0000 Subject: [PATCH] Finish the switch to the softintr(9) framework. To make this work, we now have to use separate handler lists for hardware and software interrupts as the soft interrupt handlers do not return an `interrupt handled' status. Thanks to Matt Fredette for providing an initial set of patches on port-sparc. --- sys/arch/sparc/dev/audioamd.c | 49 ++++++------ sys/arch/sparc/dev/fd.c | 47 ++++-------- sys/arch/sparc/dev/zs.c | 48 +++++------- sys/arch/sparc/include/intr.h | 31 +++++++- sys/arch/sparc/sparc/intr.c | 136 +++++++++++++++++++++++++++------- 5 files changed, 192 insertions(+), 119 deletions(-) diff --git a/sys/arch/sparc/dev/audioamd.c b/sys/arch/sparc/dev/audioamd.c index df2743ab306b..8a34a5ad0688 100644 --- a/sys/arch/sparc/dev/audioamd.c +++ b/sys/arch/sparc/dev/audioamd.c @@ -1,4 +1,4 @@ -/* $NetBSD: audioamd.c,v 1.13 2002/10/15 13:49:52 jdc Exp $ */ +/* $NetBSD: audioamd.c,v 1.14 2002/12/09 16:11:50 pk Exp $ */ /* NetBSD: am7930_sparc.c,v 1.44 1999/03/14 22:29:00 jonathan Exp */ /* @@ -64,20 +64,9 @@ /* interrupt interfaces */ #ifdef AUDIO_C_HANDLER int am7930hwintr __P((void *)); -#if defined(SUN4M) -#define AUDIO_SET_SWINTR do { \ - if (CPU_ISSUN4M) \ - raise(0, 4); \ - else \ - ienab_bis(IE_L4); \ -} while(0); -#else -#define AUDIO_SET_SWINTR ienab_bis(IE_L4) -#endif /* defined(SUN4M) */ -#else -struct auio *auiop; #endif /* AUDIO_C_HANDLER */ -int am7930swintr __P((void *)); +struct auio *auiop; +void am7930swintr __P((void *)); /* * interrupt-handler status @@ -102,6 +91,7 @@ struct audioamd_softc { /* sc_au is special in that the hardware interrupt handler uses it */ struct auio sc_au; /* recv and xmit buffers, etc */ #define sc_intrcnt sc_au.au_intrcnt /* statistics */ + void *sc_sicookie; /* softintr(9) cookie */ }; void audioamd_mainbus_attach __P((struct device *, @@ -306,8 +296,6 @@ audioamd_attach(sc, pri) int pri; { - printf(" softpri %d\n", PIL_AUSOFT); - /* * Set up glue for MI code early; we use some of it here. */ @@ -315,8 +303,8 @@ audioamd_attach(sc, pri) am7930_init(&sc->sc_am7930, AUDIOAMD_POLL_MODE); -#ifndef AUDIO_C_HANDLER auiop = &sc->sc_au; +#ifndef AUDIO_C_HANDLER (void)bus_intr_establish(sc->sc_bt, pri, IPL_AUDIO, BUS_INTR_ESTABLISH_FASTTRAP, (int (*) __P((void *)))amd7930_trap, NULL); @@ -324,9 +312,16 @@ audioamd_attach(sc, pri) (void)bus_intr_establish(sc->sc_bt, pri, IPL_AUDIO, 0, am7930hwintr, sc); #endif - (void)bus_intr_establish(sc->sc_bt, PIL_AUSOFT, IPL_AUDIO, - BUS_INTR_ESTABLISH_SOFTINTR, - am7930swintr, sc); + + sc->sc_sicookie = softintr_establish(IPL_SOFTAUDIO, am7930swintr, sc); + if (sc->sc_sicookie == NULL) { + printf("\n%s: cannot establish software interrupt\n", + sc->sc_am7930.sc_dev.dv_xname); + return; + } + + printf(" softpri %d\n", IPL_SOFTAUDIO); + evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, sc->sc_am7930.sc_dev.dv_xname, "intr"); @@ -436,6 +431,9 @@ am7930hwintr(v) /* clear interrupt */ k = audioamd_codec_dread(sc, AM7930_DREG_IR); + if ((k & (AM7930_IR_DTTHRSH|AM7930_IR_DRTHRSH|AM7930_IR_DSRI| + AM7930_IR_DERI|AM7930_IR_BBUFF)) == 0) + return (0); /* receive incoming data */ d = au->au_rdata; @@ -445,7 +443,7 @@ am7930hwintr(v) au->au_rdata++; if (d == e) { DPRINTFN(1, ("am7930hwintr: swintr(r) requested")); - AUDIO_SET_SWINTR; + softintr_schedule(sc->sc_sicookie); } } @@ -457,7 +455,7 @@ am7930hwintr(v) au->au_pdata++; if (d == e) { DPRINTFN(1, ("am7930hwintr: swintr(p) requested")); - AUDIO_SET_SWINTR; + softintr_schedule(sc->sc_sicookie); } } @@ -466,13 +464,13 @@ am7930hwintr(v) } #endif /* AUDIO_C_HANDLER */ -int +void am7930swintr(sc0) void *sc0; { struct audioamd_softc *sc = sc0; struct auio *au; - int s, ret = 0; + int s; DPRINTFN(1, ("audiointr: sc=%p\n", sc);); @@ -480,17 +478,14 @@ am7930swintr(sc0) s = splaudio(); if (au->au_rdata > au->au_rend && sc->sc_rintr != NULL) { splx(s); - ret = 1; (*sc->sc_rintr)(sc->sc_rarg); s = splaudio(); } if (au->au_pdata > au->au_pend && sc->sc_pintr != NULL) { splx(s); - ret = 1; (*sc->sc_pintr)(sc->sc_parg); } else splx(s); - return (ret); } diff --git a/sys/arch/sparc/dev/fd.c b/sys/arch/sparc/dev/fd.c index 43384c2f185b..0d935a31dbb0 100644 --- a/sys/arch/sparc/dev/fd.c +++ b/sys/arch/sparc/dev/fd.c @@ -1,4 +1,4 @@ -/* $NetBSD: fd.c,v 1.96 2002/11/01 11:31:53 mrg Exp $ */ +/* $NetBSD: fd.c,v 1.97 2002/12/09 16:11:50 pk Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -174,6 +174,8 @@ struct fdc_softc { #define sc_nstat sc_io.fdcio_nstat #define sc_status sc_io.fdcio_status #define sc_intrcnt sc_io.fdcio_intrcnt + + void *sc_sicookie; /* softintr(9) cookie */ }; extern struct fdcio *fdciop; /* I/O descriptor used in fdintr.s */ @@ -302,7 +304,7 @@ void fdctimeout __P((void *arg)); void fdcpseudointr __P((void *arg)); int fdc_c_hwintr __P((void *)); void fdchwintr __P((void)); -int fdcswintr __P((void *)); +void fdcswintr __P((void *)); int fdcstate __P((struct fdc_softc *)); void fdcretry __P((struct fdc_softc *fdc)); void fdfinish __P((struct fd_softc *fd, struct buf *bp)); @@ -318,23 +320,6 @@ static void establish_chip_type __P(( bus_space_handle_t)); -#if PIL_FDSOFT == 4 -#define IE_FDSOFT IE_L4 -#else -#error 4 -#endif - -#if defined(SUN4M) -#define FD_SET_SWINTR do { \ - if (CPU_ISSUN4M) \ - raise(0, PIL_FDSOFT); \ - else \ - ienab_bis(IE_L4); \ -} while(0) -#else -#define FD_SET_SWINTR ienab_bis(IE_FDSOFT) -#endif /* defined(SUN4M) */ - #define OBP_FDNAME (CPU_ISSUN4M ? "SUNW,fdtwo" : "fd") int @@ -624,8 +609,6 @@ fdcattach(fdc, pri) code = '2'; } - printf(" softpri %d: chip 8207%c\n", PIL_FDSOFT, code); - /* * Configure controller; enable FIFO, Implied seek, no POLL mode?. * Note: CFG_EFIFO is active-low, initial threshold value: 8 @@ -651,13 +634,13 @@ fdcattach(fdc, pri) } } - if (bus_intr_establish(fdc->sc_bustag, PIL_FDSOFT, IPL_BIO, - BUS_INTR_ESTABLISH_SOFTINTR, - fdcswintr, fdc) == NULL) { - printf("%s: cannot register interrupt handler\n", + fdc->sc_sicookie = softintr_establish(IPL_SOFTFDC, fdcswintr, fdc); + if (fdc->sc_sicookie == NULL) { + printf("\n%s: cannot register soft interrupt handler\n", fdc->sc_dev.dv_xname); return (-1); } + printf(" softpri %d: chip 8207%c\n", IPL_SOFTFDC, code); evcnt_attach_dynamic(&fdc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, fdc->sc_dev.dv_xname, "intr"); @@ -1320,7 +1303,7 @@ fdc_c_hwintr(arg) fdc->sc_istatus = FDC_ISTATUS_ERROR; else fdc->sc_istatus = FDC_ISTATUS_DONE; - FD_SET_SWINTR; + softintr_schedule(fdc->sc_sicookie); return (1); case FDC_ITASK_DMA: /* Proceed with pseudo-dma below */ @@ -1328,7 +1311,7 @@ fdc_c_hwintr(arg) default: printf("fdc: stray hard interrupt: itask=%d\n", fdc->sc_itask); fdc->sc_istatus = FDC_ISTATUS_SPURIOUS; - FD_SET_SWINTR; + softintr_schedule(fdc->sc_sicookie); return (1); } @@ -1347,7 +1330,7 @@ fdc_c_hwintr(arg) if ((msr & NE7_NDM) == 0) { fdcresult(fdc); fdc->sc_istatus = FDC_ISTATUS_DONE; - FD_SET_SWINTR; + softintr_schedule(fdc->sc_sicookie); #ifdef FD_DEBUG if (fdc_debug > 1) printf("fdc: overrun: tc = %d\n", fdc->sc_tc); @@ -1368,14 +1351,14 @@ fdc_c_hwintr(arg) fdc->sc_istatus = FDC_ISTATUS_DONE; FTC_FLIP; fdcresult(fdc); - FD_SET_SWINTR; + softintr_schedule(fdc->sc_sicookie); break; } } return (1); } -int +void fdcswintr(arg) void *arg; { @@ -1384,7 +1367,7 @@ fdcswintr(arg) if (fdc->sc_istatus == FDC_ISTATUS_NONE) /* This (software) interrupt is not for us */ - return (0); + return; switch (fdc->sc_istatus) { case FDC_ISTATUS_ERROR: @@ -1398,7 +1381,7 @@ fdcswintr(arg) s = splbio(); fdcstate(fdc); splx(s); - return (1); + return; } int diff --git a/sys/arch/sparc/dev/zs.c b/sys/arch/sparc/dev/zs.c index 96d0f18522b5..f0bb60d3e1b5 100644 --- a/sys/arch/sparc/dev/zs.c +++ b/sys/arch/sparc/dev/zs.c @@ -1,4 +1,4 @@ -/* $NetBSD: zs.c,v 1.92 2002/10/09 08:56:25 jdc Exp $ */ +/* $NetBSD: zs.c,v 1.93 2002/12/09 16:11:51 pk Exp $ */ /*- * Copyright (c) 1996 The NetBSD Foundation, Inc. @@ -96,19 +96,6 @@ int zs_def_cflag = (CREAD | CS8 | HUPCL); */ #define PCLK (9600 * 512) /* PCLK pin input clock rate */ -/* - * Select software interrupt bit based on TTY ipl. - */ -#if PIL_TTY == 1 -# define IE_ZSSOFT IE_L1 -#elif PIL_TTY == 4 -# define IE_ZSSOFT IE_L4 -#elif PIL_TTY == 6 -# define IE_ZSSOFT IE_L6 -#else -# error "no suitable software interrupt bit" -#endif - #define ZS_DELAY() (CPU_ISSUN4C ? (0) : delay(2)) /* The layout of this is hardware-dependent (padding, order). */ @@ -192,9 +179,12 @@ CFATTACH_DECL(zs_obio, sizeof(struct zsc_softc), extern struct cfdriver zs_cd; +/* softintr(9) cookie, shared by all instances of this driver */ +static void *zs_sicookie; + /* Interrupt handlers. */ static int zshard __P((void *)); -static int zssoft __P((void *)); +static void zssoft __P((void *)); static int zs_get_speed __P((struct zs_chanstate *)); @@ -435,7 +425,15 @@ zs_attach(zsc, zsd, pri) return; } - printf(" softpri %d\n", PIL_TTY); + if (!didintr) { + zs_sicookie = softintr_establish(IPL_SOFTSERIAL, zssoft, NULL); + if (zs_sicookie == NULL) { + printf("\n%s: cannot establish soft int handler\n", + zsc->zsc_dev.dv_xname); + return; + } + } + printf(" softpri %d\n", IPL_SOFTSERIAL); /* * Initialize software state for each channel. @@ -520,10 +518,6 @@ zs_attach(zsc, zsd, pri) prevpri = pri; bus_intr_establish(zsc->zsc_bustag, pri, IPL_SERIAL, 0, zshard, NULL); - bus_intr_establish(zsc->zsc_bustag, PIL_TTY, - IPL_SOFTSERIAL, - BUS_INTR_ESTABLISH_SOFTINTR, - zssoft, NULL); } else if (pri != prevpri) panic("broken zs interrupt scheme"); @@ -606,13 +600,8 @@ zshard(arg) /* We are at splzs here, so no need to lock. */ if (softreq && (zssoftpending == 0)) { - zssoftpending = IE_ZSSOFT; -#if defined(SUN4M) - if (CPU_ISSUN4M) - raise(0, PIL_TTY); - else -#endif - ienab_bis(IE_ZSSOFT); + zssoftpending = 1; + softintr_schedule(zs_sicookie); } return (rval); } @@ -620,7 +609,7 @@ zshard(arg) /* * Similar scheme as for zshard (look at all of them) */ -static int +static void zssoft(arg) void *arg; { @@ -629,7 +618,7 @@ zssoft(arg) /* This is not the only ISR on this IPL. */ if (zssoftpending == 0) - return (0); + return; /* * The soft intr. bit will be set by zshard only if @@ -649,7 +638,6 @@ zssoft(arg) (void)zsc_intr_soft(zsc); } splx(s); - return (1); } diff --git a/sys/arch/sparc/include/intr.h b/sys/arch/sparc/include/intr.h index 07fbe40bd629..093ad95a2f98 100644 --- a/sys/arch/sparc/include/intr.h +++ b/sys/arch/sparc/include/intr.h @@ -1,4 +1,4 @@ -/* $NetBSD: intr.h,v 1.4 2002/12/06 15:36:45 pk Exp $ */ +/* $NetBSD: intr.h,v 1.5 2002/12/09 16:11:52 pk Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -60,10 +60,33 @@ #if defined(_KERNEL) && !defined(_LOCORE) void * -softintr_establish __P((int level, void (*fun)(void *), void *arg)); +softintr_establish(int level, void (*fun)(void *), void *arg); void -softintr_disestablish __P((void *cookie)); +softintr_disestablish(void *cookie); -#define softintr_schedule(cookie) setsoftint() +/* + * NB that softintr_schedule() casts the cookie to an int *. + * This is to get the sic_pilreq member of the softintr_cookie + * structure, which is otherwise internal to intr.c. + */ +#if defined(SUN4M) || defined(SUN4D) +extern void raise __P((int, int)); +#if !(defined(SUN4) || defined(SUN4C)) +#define softintr_schedule(cookie) raise(0, *((int *) (cookie))) +#else /* both defined */ +#define softintr_schedule(cookie) do { \ + if (CPU_ISSUN4M || CPU_ISSUN4D) \ + raise(0, *((int *)(cookie))); \ + else \ + ienab_bis(*((int *)(cookie))); \ +} while (0) +#endif /* SUN4 || SUN4C */ +#else /* SUN4M || SUN4D */ +#define softintr_schedule(cookie) ienab_bis(*((int *) (cookie))) +#endif /* SUN4M || SUN4D */ + +#if 0 +void softintr_schedule(void *cookie); +#endif #endif /* KERNEL && !_LOCORE */ diff --git a/sys/arch/sparc/sparc/intr.c b/sys/arch/sparc/sparc/intr.c index 9201f8aad71a..a57c4cb0ec19 100644 --- a/sys/arch/sparc/sparc/intr.c +++ b/sys/arch/sparc/sparc/intr.c @@ -1,4 +1,4 @@ -/* $NetBSD: intr.c,v 1.61 2002/12/06 16:04:12 pk Exp $ */ +/* $NetBSD: intr.c,v 1.62 2002/12/09 16:11:53 pk Exp $ */ /* * Copyright (c) 1992, 1993 @@ -409,6 +409,41 @@ struct intrhand *intrhand[15] = { NULL, /* 14 = counter 1 = profiling timer */ }; +/* + * Soft interrupts use a separate set of handler chains. + * This is necessary since soft interrupt handlers do not return a value + * and therefore cannot be mixed with hardware interrupt handlers on a + * shared handler chain. + */ +struct intrhand *sintrhand[15] = { NULL }; + +static void ih_insert(struct intrhand **head, struct intrhand *ih) +{ + struct intrhand **p, *q; + /* + * This is O(N^2) for long chains, but chains are never long + * and we do want to preserve order. + */ + for (p = head; (q = *p) != NULL; p = &q->ih_next) + continue; + *p = ih; + ih->ih_next = NULL; +} + +static void ih_remove(struct intrhand **head, struct intrhand *ih) +{ + struct intrhand **p, *q; + + for (p = head; (q = *p) != ih; p = &q->ih_next) + continue; + if (q == NULL) + panic("intr_remove: intrhand %p fun %p arg %p", + ih, ih->ih_fun, ih->ih_arg); + + *p = q->ih_next; + q->ih_next = NULL; +} + static int fastvec; /* marks fast vectors (see below) */ #ifdef DIAGNOSTIC extern int sparc_interrupt4m[]; @@ -425,7 +460,6 @@ intr_establish(level, classipl, ih) int classipl; struct intrhand *ih; { - struct intrhand **p, *q; #ifdef DIAGNOSTIC struct trapvec *tv; int displ; @@ -466,14 +500,7 @@ intr_establish(level, classipl, ih) /* pre-shift to PIL field in %psr */ ih->ih_classipl = (classipl << 8) & PSR_PIL; - /* - * This is O(N^2) for long chains, but chains are never long - * and we do want to preserve order. - */ - for (p = &intrhand[level]; (q = *p) != NULL; p = &q->ih_next) - continue; - *p = ih; - ih->ih_next = NULL; + ih_insert(&intrhand[level], ih); splx(s); } @@ -482,16 +509,7 @@ intr_disestablish(level, ih) int level; struct intrhand *ih; { - struct intrhand **p, *q; - - for (p = &intrhand[level]; (q = *p) != ih; p = &q->ih_next) - continue; - if (q == NULL) - panic("intr_disestablish: level %d intrhand %p fun %p arg %p", - level, ih, ih->ih_fun, ih->ih_arg); - - *p = q->ih_next; - q->ih_next = NULL; + ih_remove(&intrhand[level], ih); } /* @@ -544,6 +562,20 @@ intr_fasttrap(level, vec) splx(s); } +/* + * This is a softintr cookie. NB that sic_pilreq MUST be the + * first element in the struct, because the softintr_schedule() + * macro in intr.h casts cookies to int * to get it. On a + * sun4m, sic_pilreq is an actual processor interrupt level that + * is passed to raise(), and on a sun4 or sun4c sic_pilreq is a + * bit to set in the interrupt enable register with ienab_bis(). + */ +struct softintr_cookie { + int sic_pilreq; /* MUST be first! */ + int sic_level; + struct intrhand sic_hand; +}; + /* * softintr_init(): initialise the MI softintr system. */ @@ -564,15 +596,47 @@ softintr_establish(level, fun, arg) void (*fun) __P((void *)); void *arg; { + struct softintr_cookie *sic; struct intrhand *ih; + int pilreq; - ih = malloc(sizeof(*ih), M_DEVBUF, 0); - bzero(ih, sizeof(*ih)); + /* + * On a sun4m, the processor interrupt level is stored + * in the softintr cookie to be passed to raise(). + * + * On a sun4 or sun4c the appropriate bit to set + * in the interrupt enable register is stored in + * the softintr cookie to be passed to ienab_bis(). + */ + pilreq = level; + if (CPU_ISSUN4 || CPU_ISSUN4C) { + /* Select the most suitable of three available softint levels */ + if (level >= 1 && level < 4) + pilreq = IE_L1; + else if (level >= 4 && level < 6) + pilreq = IE_L4; + else { + pilreq = IE_L6; + } + } + + sic = malloc(sizeof(*sic), M_DEVBUF, 0); + sic->sic_level = level; + sic->sic_pilreq = pilreq; + ih = &sic->sic_hand; ih->ih_fun = (int (*) __P((void *)))fun; ih->ih_arg = arg; - ih->ih_next = 0; - intr_establish(1, level, ih); - return (void *)ih; + + /* + * Always run the handler at the requested level, which might + * be higher than the hardware can provide. + * + * pre-shift to PIL field in %psr + */ + ih->ih_classipl = (level << 8) & PSR_PIL; + + ih_insert(&sintrhand[level], ih); + return (void *)sic; } /* @@ -583,11 +647,31 @@ void softintr_disestablish(cookie) void *cookie; { + struct softintr_cookie *sic = cookie; - intr_disestablish(1, cookie); + ih_remove(&sintrhand[sic->sic_level], &sic->sic_hand); free(cookie, M_DEVBUF); } +#if 0 +void +softintr_schedule(cookie) + void *cookie; +{ + struct softintr_cookie *sic = cookie; + if (CPU_ISSUN4M || CPU_ISSUN4D) { +#if defined(SUN4M) || defined(SUN4D) + extern void raise(int,int); + raise(0, sic->sic_pilreq); +#endif + } else { +#if defined(SUN4) || defined(SUN4C) + ienab_bis(sic->sic_pilreq); +#endif + } +} +#endif + #ifdef MULTIPROCESSOR /* * Called by interrupt stubs, etc., to lock/unlock the kernel.