--- //depot/vendor/freebsd/src/sys/dev/ppbus/if_plip.c 2008/08/22 18:45:13 +++ //depot/user/jhb/acpipci/dev/ppbus/if_plip.c 2008/08/22 19:57:41 @@ -193,34 +193,7 @@ static int lp_probe(device_t dev) { - device_t ppbus = device_get_parent(dev); - struct lp_data *lp; - int zero = 0; - uintptr_t irq; - - lp = DEVTOSOFTC(dev); - - /* retrieve the ppbus irq */ - BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); - - /* if we haven't interrupts, the probe fails */ - if (irq == -1) { - device_printf(dev, "not an interrupt driven port, failed.\n"); - return (ENXIO); - } - /* reserve the interrupt resource, expecting irq is available to continue */ - lp->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1, - RF_SHAREABLE); - if (lp->res_irq == 0) { - device_printf(dev, "cannot reserve interrupt, failed.\n"); - return (ENXIO); - } - - /* - * lp dependent initialisation. - */ - device_set_desc(dev, "PLIP network interface"); return (0); @@ -231,6 +204,18 @@ { struct lp_data *lp = DEVTOSOFTC(dev); struct ifnet *ifp; + int rid = 0; + + /* + * Reserve the interrupt resource. If we don't have one, the + * attach failes. + */ + lp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE); + if (lp->res_irq == 0) { + device_printf(dev, "cannot reserve interrupt, failed.\n"); + return (ENXIO); + } ifp = lp->sc_ifp = if_alloc(IFT_PARA); if (ifp == NULL) { --- //depot/vendor/freebsd/src/sys/dev/ppbus/lpt.c 2007/02/23 12:24:01 +++ //depot/user/jhb/acpipci/dev/ppbus/lpt.c 2008/08/22 15:51:21 @@ -367,9 +367,8 @@ { device_t ppbus = device_get_parent(dev); struct lpt_data *sc = DEVTOSOFTC(dev); - int zero = 0, unit = device_get_unit(dev); + int rid = 0, unit = device_get_unit(dev); int error; - intptr_t irq; sc->sc_primed = 0; /* not primed yet */ @@ -383,14 +382,9 @@ /* check if we can use interrupt, should be done by ppc stuff */ lprintf(("oldirq %x\n", sc->sc_irq)); - /* retrieve the ppbus irq */ - BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); - - if (irq > 0) { - /* declare our interrupt handler */ - sc->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, - &zero, irq, irq, 1, RF_SHAREABLE); - } + /* declare our interrupt handler */ + sc->intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE); if (sc->intr_resource) { sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ; device_printf(dev, "Interrupt-driven port\n"); @@ -398,7 +392,7 @@ sc->sc_irq = 0; device_printf(dev, "Polled port\n"); } - lprintf(("irq %x %x\n", (int)irq, sc->sc_irq)); + lprintf(("irq %x\n", sc->sc_irq)); lpt_release_ppbus(dev); --- //depot/vendor/freebsd/src/sys/dev/ppbus/ppbconf.c 2008/08/22 18:45:13 +++ //depot/user/jhb/acpipci/dev/ppbus/ppbconf.c 2008/08/22 19:57:41 @@ -121,9 +121,6 @@ case PPBUS_IVAR_AVM: *val = (u_long)ppbdev->avm; break; - case PPBUS_IVAR_IRQ: - BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_IRQ, val); - break; default: return (ENOENT); } @@ -383,38 +380,9 @@ #endif /* !DONTPROBE_1284 */ -static void -ppbus_dummy_intr(void *arg) -{ -} - static int ppbus_attach(device_t dev) { - struct ppb_data *ppb = (struct ppb_data *)device_get_softc(dev); - uintptr_t irq; - int error, rid; - - /* Attach a dummy interrupt handler to suck up any stray interrupts. */ - BUS_READ_IVAR(device_get_parent(dev), dev, PPC_IVAR_IRQ, &irq); - - if (irq > 0) { - rid = 0; - ppb->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, - irq, 1, RF_SHAREABLE); - if (ppb->irq_res != NULL) { - error = bus_setup_intr(dev, ppb->irq_res, - INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppbus_dummy_intr, - ppb, &ppb->intr_cookie); - if (error) { - device_printf(dev, - "failed to setup interrupt handler\n"); - bus_release_resource(dev, SYS_RES_IRQ, 0, - ppb->irq_res); - return (error); - } - } - } /* Locate our children */ bus_generic_probe(dev); @@ -433,7 +401,6 @@ static int ppbus_detach(device_t dev) { - struct ppb_data *ppb = (struct ppb_data *)device_get_softc(dev); device_t *children; int nchildren, i; @@ -445,10 +412,6 @@ free(children, M_TEMP); } - if (ppb->irq_res != NULL) { - bus_teardown_intr(dev, ppb->irq_res, ppb->intr_cookie); - bus_release_resource(dev, SYS_RES_IRQ, 0, ppb->irq_res); - } return (0); } @@ -602,7 +565,8 @@ DEVMETHOD(bus_write_ivar, ppbus_write_ivar), DEVMETHOD(bus_setup_intr, ppbus_setup_intr), DEVMETHOD(bus_teardown_intr, ppbus_teardown_intr), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), { 0, 0 } }; --- //depot/vendor/freebsd/src/sys/dev/ppbus/ppbconf.h 2008/01/10 23:45:34 +++ //depot/user/jhb/acpipci/dev/ppbus/ppbconf.h 2008/08/22 15:51:21 @@ -179,7 +179,6 @@ */ #define PPBUS_IVAR_MODE 0 #define PPBUS_IVAR_AVM 1 -#define PPBUS_IVAR_IRQ 2 /* other fields are reserved to the ppbus internals */ @@ -216,7 +215,6 @@ /* Parallel Port Chipset IVARS */ /* elsewhere XXX */ #define PPC_IVAR_EPP_PROTO 0 -#define PPC_IVAR_IRQ 1 /* * Maximum size of the PnP info string @@ -248,9 +246,6 @@ * NIBBLE, PS2, EPP or ECP */ void *ppb_owner; /* device which owns the bus */ - - struct resource *irq_res; - void *intr_cookie; }; #ifdef _KERNEL --- //depot/vendor/freebsd/src/sys/dev/ppbus/ppi.c 2007/02/23 19:35:55 +++ //depot/user/jhb/acpipci/dev/ppbus/ppi.c 2008/08/22 15:51:21 @@ -163,16 +163,12 @@ ppi_attach(device_t dev) { #ifdef PERIPH_1284 - uintptr_t irq; - int zero = 0; + int rid = 0; struct ppi_data *ppi = DEVTOSOFTC(dev); - /* retrive the irq */ - BUS_READ_IVAR(device_get_parent(dev), dev, PPBUS_IVAR_IRQ, &irq); - /* declare our interrupt handler */ - ppi->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, - &zero, irq, irq, 1, RF_ACTIVE); + ppi->intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); #endif /* PERIPH_1284 */ make_dev(&ppi_cdevsw, device_get_unit(dev), /* XXX cleanup */ --- //depot/vendor/freebsd/src/sys/dev/ppbus/pps.c 2007/02/23 12:24:01 +++ //depot/user/jhb/acpipci/dev/ppbus/pps.c 2008/08/22 15:51:21 @@ -107,18 +107,14 @@ struct pps_data *sc = DEVTOSOFTC(dev); device_t ppbus = device_get_parent(dev); struct cdev *d; - intptr_t irq; - int i, unit, zero = 0; + int i, unit, rid = 0; mtx_init(&sc->mtx, device_get_nameunit(dev), "pps", MTX_SPIN); - /* retrieve the ppbus irq */ - BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); + + /* declare our interrupt handler */ + sc->intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE); - if (irq > 0) { - /* declare our interrupt handler */ - sc->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, - &zero, irq, irq, 1, RF_SHAREABLE); - } /* interrupts seem mandatory */ if (sc->intr_resource == NULL) return (ENXIO); --- //depot/vendor/freebsd/src/sys/dev/ppc/ppc.c 2008/08/22 18:45:13 +++ //depot/user/jhb/acpipci/dev/ppc/ppc.c 2008/08/22 19:57:41 @@ -32,10 +32,12 @@ #include #include +#include #include +#include #include -#include #include +#include #include #include @@ -1515,10 +1517,21 @@ static void ppcintr(void *arg) { - device_t dev = (device_t)arg; - struct ppc_data *ppc = (struct ppc_data *)device_get_softc(dev); + struct ppc_data *ppc = arg; u_char ctr, ecr, str; + /* + * If we have any child interrupt handlers registered, let + * them handle this interrupt. + * + * XXX: If DMA is in progress should we just complete that w/o + * doing this? + */ + if (ppc->ppc_child_handlers > 0) { + intr_event_execute_handlers(curproc, ppc->ppc_intr_event); + return; + } + str = r_str(ppc); ctr = r_ctr(ppc); ecr = r_ecr(ppc); @@ -1790,8 +1803,8 @@ ppc_attach(device_t dev) { struct ppc_data *ppc = DEVTOSOFTC(dev); - device_t ppbus; + int error; device_printf(dev, "%s chipset (%s) in %s mode%s\n", ppc_models[ppc->ppc_model], ppc_avms[ppc->ppc_avm], @@ -1802,6 +1815,30 @@ device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n", ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr); + if (ppc->res_irq) { + /* + * Create an interrupt event to manage the handlers of + * child devices. + */ + error = intr_event_create(&ppc->ppc_intr_event, ppc, 0, -1, + NULL, NULL, NULL, NULL, "%s:", device_get_nameunit(dev)); + if (error) { + device_printf(dev, + "failed to create interrupt event: %d\n", error); + return (error); + } + + /* default to the tty mask for registration */ /* XXX */ + error = bus_setup_intr(dev, ppc->res_irq, INTR_TYPE_TTY, + NULL, ppcintr, ppc, &ppc->intr_cookie); + if (error) { + device_printf(dev, + "failed to register interrupt handler: %d\n", + error); + return (error); + } + } + /* add ppbus as a child of this isa to parallel bridge */ ppbus = device_add_child(dev, "ppbus", -1); @@ -1810,17 +1847,6 @@ */ device_probe_and_attach(ppbus); - /* register the ppc interrupt handler as default */ - if (ppc->res_irq) { - /* default to the tty mask for registration */ /* XXX */ - if (bus_setup_intr(dev, ppc->res_irq, INTR_TYPE_TTY, - NULL, ppcintr, dev, &ppc->intr_cookie) == 0) { - - /* remember the ppcintr is registered */ - ppc->ppc_registered = 1; - } - } - return (0); } @@ -1935,9 +1961,6 @@ case PPC_IVAR_EPP_PROTO: *val = (u_long)ppc->ppc_epp; break; - case PPC_IVAR_IRQ: - *val = (u_long)ppc->ppc_irq; - break; default: return (ENOENT); } @@ -1946,63 +1969,84 @@ } /* - * Resource is useless here since ppbus devices' interrupt handlers are - * multiplexed to the same resource initially allocated by ppc + * We allow child devices to allocate an IRQ resource at rid 0 for their + * interrupt handlers. */ -int -ppc_setup_intr(device_t bus, device_t child, struct resource *r, int flags, - driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep) +struct resource * +ppc_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) { - int error; struct ppc_data *ppc = DEVTOSOFTC(bus); - if (ppc->ppc_registered) { - /* XXX refuse registration if DMA is in progress */ + switch (type) { + case SYS_RES_IRQ: + if (*rid == 0) + return (ppc->res_irq); + break; + } + return (NULL); +} - /* first, unregister the default interrupt handler */ - if ((error = BUS_TEARDOWN_INTR(device_get_parent(bus), - bus, ppc->res_irq, ppc->intr_cookie))) - return (error); +int +ppc_release_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ +#ifdef INVARIANTS + struct ppc_data *ppc = DEVTOSOFTC(bus); +#endif -/* bus_deactivate_resource(bus, SYS_RES_IRQ, ppc->rid_irq, */ -/* ppc->res_irq); */ - - /* DMA/FIFO operation won't be possible anymore */ - ppc->ppc_registered = 0; + switch (type) { + case SYS_RES_IRQ: + if (rid == 0) { + KASSERT(r == ppc->res_irq, + ("ppc child IRQ resource mismatch")); + return (0); + } + break; } - - /* - * pass registration to the upper layer, ignore the incoming - * resource - */ - return (BUS_SETUP_INTR(device_get_parent(bus), child, - r, flags, filt, ihand, arg, cookiep)); + return (EINVAL); } /* - * When no underlying device has a registered interrupt, register the ppc - * layer one + * If a child wants to add a handler for our IRQ, add it to our interrupt + * event. Otherwise, fail the request. */ int -ppc_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) +ppc_setup_intr(device_t bus, device_t child, struct resource *r, int flags, + driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep) { + struct ppc_data *ppc = DEVTOSOFTC(bus); int error; - struct ppc_data *ppc = DEVTOSOFTC(bus); - device_t parent = device_get_parent(bus); + + if (r != ppc->res_irq) + return (EINVAL); + + /* We don't allow filters. */ + if (filt != NULL) + return (EINVAL); - /* pass unregistration to the upper layer */ - if ((error = BUS_TEARDOWN_INTR(parent, child, r, ih))) - return (error); + error = intr_event_add_handler(ppc->ppc_intr_event, + device_get_nameunit(child), NULL, ihand, arg, intr_priority(flags), + flags, cookiep); + if (error == 0) + ppc->ppc_child_handlers++; + return (error); +} - /* default to the tty mask for registration */ /* XXX */ - if (ppc->ppc_irq && - !(error = BUS_SETUP_INTR(parent, bus, ppc->res_irq, - INTR_TYPE_TTY, NULL, ppcintr, bus, &ppc->intr_cookie))) { +int +ppc_teardown_intr(device_t bus, device_t child, struct resource *r, void *cookie) +{ + struct ppc_data *ppc = DEVTOSOFTC(bus); + int error; - /* remember the ppcintr is registered */ - ppc->ppc_registered = 1; - } + if (r != ppc->res_irq) + return (EINVAL); + KASSERT(intr_handler_source(cookie) == ppc, + ("ppc_teardown_intr: source mismatch")); + error = intr_event_remove_handler(cookie); + if (error == 0) + ppc->ppc_child_handlers--; return (error); } --- //depot/vendor/freebsd/src/sys/dev/ppc/ppc_acpi.c 2008/08/22 18:45:13 +++ //depot/user/jhb/acpipci/dev/ppc/ppc_acpi.c 2008/08/22 19:57:41 @@ -65,7 +65,8 @@ DEVMETHOD(bus_read_ivar, ppc_read_ivar), DEVMETHOD(bus_setup_intr, ppc_setup_intr), DEVMETHOD(bus_teardown_intr, ppc_teardown_intr), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_alloc_resource, ppc_alloc_resource), + DEVMETHOD(bus_release_resource, ppc_release_resource), /* ppbus interface */ DEVMETHOD(ppbus_io, ppc_io), --- //depot/vendor/freebsd/src/sys/dev/ppc/ppc_isa.c 2008/08/22 18:45:13 +++ //depot/user/jhb/acpipci/dev/ppc/ppc_isa.c 2008/08/22 19:57:41 @@ -67,7 +67,8 @@ DEVMETHOD(bus_read_ivar, ppc_read_ivar), DEVMETHOD(bus_setup_intr, ppc_setup_intr), DEVMETHOD(bus_teardown_intr, ppc_teardown_intr), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_alloc_resource, ppc_alloc_resource), + DEVMETHOD(bus_release_resource, ppc_release_resource), /* ppbus interface */ DEVMETHOD(ppbus_io, ppc_io), @@ -147,7 +148,7 @@ int s, error = 0; int spin; - if (!(ppc->ppc_avm & PPB_ECP) || !ppc->ppc_registered) + if (!(ppc->ppc_avm & PPB_ECP)) return (EINVAL); if (ppc->ppc_dmachan == 0) return (EINVAL); --- //depot/vendor/freebsd/src/sys/dev/ppc/ppc_pci.c 2006/04/24 23:36:04 +++ //depot/user/jhb/acpipci/dev/ppc/ppc_pci.c 2008/08/22 15:51:21 @@ -55,7 +55,8 @@ DEVMETHOD(bus_read_ivar, ppc_read_ivar), DEVMETHOD(bus_setup_intr, ppc_setup_intr), DEVMETHOD(bus_teardown_intr, ppc_teardown_intr), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_alloc_resource, ppc_alloc_resource), + DEVMETHOD(bus_release_resource, ppc_release_resource), /* ppbus interface */ DEVMETHOD(ppbus_io, ppc_io), --- //depot/vendor/freebsd/src/sys/dev/ppc/ppc_puc.c 2006/04/28 21:25:23 +++ //depot/user/jhb/acpipci/dev/ppc/ppc_puc.c 2008/08/22 15:51:21 @@ -57,7 +57,8 @@ DEVMETHOD(bus_read_ivar, ppc_read_ivar), DEVMETHOD(bus_setup_intr, ppc_setup_intr), DEVMETHOD(bus_teardown_intr, ppc_teardown_intr), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_alloc_resource, ppc_alloc_resource), + DEVMETHOD(bus_release_resource, ppc_release_resource), /* ppbus interface */ DEVMETHOD(ppbus_io, ppc_io), --- //depot/vendor/freebsd/src/sys/dev/ppc/ppcreg.h 2008/08/22 18:45:13 +++ //depot/user/jhb/acpipci/dev/ppc/ppcreg.h 2008/08/22 19:57:41 @@ -109,7 +109,8 @@ void *intr_cookie; - int ppc_registered; /* 1 if ppcintr() is the registered interrupt */ + struct intr_event *ppc_intr_event; + int ppc_child_handlers; }; /* --- //depot/vendor/freebsd/src/sys/dev/ppc/ppcvar.h 2007/02/23 12:24:01 +++ //depot/user/jhb/acpipci/dev/ppc/ppcvar.h 2008/08/22 15:51:21 @@ -42,6 +42,10 @@ int ppc_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *filt, void (*)(void *), void *, void **); int ppc_teardown_intr(device_t, device_t, struct resource *, void *); +struct resource *ppc_alloc_resource(device_t bus, device_t child, int type, + int *rid, u_long start, u_long end, u_long count, u_int flags); +int ppc_release_resource(device_t bus, device_t child, int type, int rid, + struct resource *r); void ppc_reset_epp(device_t); void ppc_ecp_sync(device_t); int ppc_setmode(device_t, int); --- //depot/vendor/freebsd/src/sys/kern/kern_intr.c 2008/07/18 07:10:14 +++ //depot/user/jhb/acpipci/kern/kern_intr.c 2008/08/22 15:51:21 @@ -1084,16 +1084,16 @@ } #endif -static void -ithread_execute_handlers(struct proc *p, struct intr_event *ie) +/* + * This is a public function for use by drivers that mux interrupt + * handlers for child devices from their interrupt handler. + */ +void +intr_event_execute_handlers(struct proc *p, struct intr_event *ie) { struct intr_handler *ih, *ihn; - /* Interrupt handlers should not sleep. */ - if (!(ie->ie_flags & IE_SOFT)) - THREAD_NO_SLEEPING(); TAILQ_FOREACH_SAFE(ih, &ie->ie_handlers, ih_next, ihn) { - /* * If this handler is marked for death, remove it from * the list of handlers and wake up the sleeper. @@ -1134,6 +1134,17 @@ if (!(ih->ih_flags & IH_MPSAFE)) mtx_unlock(&Giant); } +} + +static void +ithread_execute_handlers(struct proc *p, struct intr_event *ie) +{ + struct intr_handler *ih, *ihn; + + /* Interrupt handlers should not sleep. */ + if (!(ie->ie_flags & IE_SOFT)) + THREAD_NO_SLEEPING(); + intr_event_execute_handlers(p, ie); if (!(ie->ie_flags & IE_SOFT)) THREAD_SLEEPING_OK(); --- //depot/vendor/freebsd/src/sys/sys/interrupt.h 2008/07/18 06:25:15 +++ //depot/user/jhb/acpipci/sys/interrupt.h 2008/08/22 15:51:21 @@ -90,6 +90,16 @@ * The 'assign_cpu' hook is used to bind an interrupt source to a * specific CPU. If the interrupt cannot be bound, this function may * return an error. + * + * Note that device drivers may also use interrupt events to manage + * multiplexing interrupt interrupt handler into handlers for child + * devices. In that case, the above hooks are not used. The device + * can create an event for its interrupt resource and register child + * event handlers with that event. It can then use + * intr_event_execute_handlers() to execute non-filter handlers. + * Currently filter handlers are not supported by this, but that can + * be added by splitting out the filter loop from intr_event_handle() + * if desired. */ struct intr_event { TAILQ_ENTRY(intr_event) ie_list; @@ -157,6 +167,7 @@ int (*assign_cpu)(void *, u_char), const char *fmt, ...) __printflike(9, 10); int intr_event_destroy(struct intr_event *ie); +void intr_event_execute_handlers(struct proc *p, struct intr_event *ie); int intr_event_handle(struct intr_event *ie, struct trapframe *frame); int intr_event_remove_handler(void *cookie); int intr_getaffinity(int irq, void *mask);