From owner-p4-projects Tue Mar 19 18:43: 9 2002 Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id ED4AA37B430; Tue, 19 Mar 2002 18:40:23 -0800 (PST) Delivered-To: perforce@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id B510C37B41D for ; Tue, 19 Mar 2002 18:39:31 -0800 (PST) Received: (from perforce@localhost) by freefall.freebsd.org (8.11.6/8.11.6) id g2K2dVN60219 for perforce@freebsd.org; Tue, 19 Mar 2002 18:39:31 -0800 (PST) (envelope-from tmm@freebsd.org) Date: Tue, 19 Mar 2002 18:39:31 -0800 (PST) Message-Id: <200203200239.g2K2dVN60219@freefall.freebsd.org> X-Authentication-Warning: freefall.freebsd.org: perforce set sender to tmm@freebsd.org using -f From: Thomas Moestl Subject: PERFORCE change 8009 for review To: Perforce Change Reviews Sender: owner-p4-projects@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG http://people.freebsd.org/~peter/p4db/chv.cgi?CH=8009 Change 8009 by tmm@tmm_sparc64 on 2002/03/19 18:39:04 Integ. with sparc64-tmm: - hme fixes and cleanups. - the big fearsome ofw interrupt code rework. Affected files ... ... //depot/projects/sparc64/sys/dev/hme/if_hme.c#16 integrate ... //depot/projects/sparc64/sys/dev/hme/if_hme_pci.c#11 integrate ... //depot/projects/sparc64/sys/dev/hme/if_hme_sbus.c#5 integrate ... //depot/projects/sparc64/sys/dev/hme/if_hmevar.h#9 integrate ... //depot/projects/sparc64/sys/sparc64/ebus/ebus.c#9 integrate ... //depot/projects/sparc64/sys/sparc64/ebus/ebusvar.h#4 integrate ... //depot/projects/sparc64/sys/sparc64/include/ofw_bus.h#5 integrate ... //depot/projects/sparc64/sys/sparc64/isa/isa.c#8 integrate ... //depot/projects/sparc64/sys/sparc64/isa/ofw_isa.c#7 integrate ... //depot/projects/sparc64/sys/sparc64/pci/apb.c#8 integrate ... //depot/projects/sparc64/sys/sparc64/pci/ofw_pci.c#7 integrate ... //depot/projects/sparc64/sys/sparc64/pci/ofw_pci.h#4 integrate ... //depot/projects/sparc64/sys/sparc64/pci/psycho.c#24 integrate ... //depot/projects/sparc64/sys/sparc64/pci/psychovar.h#9 integrate ... //depot/projects/sparc64/sys/sparc64/sparc64/iommu.c#17 integrate ... //depot/projects/sparc64/sys/sparc64/sparc64/ofw_bus.c#5 integrate Differences ... ==== //depot/projects/sparc64/sys/dev/hme/if_hme.c#16 (text+ko) ==== @@ -1310,13 +1310,6 @@ HME_MAC_WRITE_4(sc, HME_MACI_TXCFG, v); if (!hme_mac_bitflip(sc, HME_MACI_TXCFG, v, 0, HME_MAC_TXCFG_ENABLE)) return; - - /* If an external transceiver is selected, enable its MII drivers */ - v = HME_MAC_READ_4(sc, HME_MACI_XIF); - v &= ~HME_MAC_XIF_MIIENABLE; - if (phy == HME_PHYAD_EXTERNAL) - v |= HME_MAC_XIF_MIIENABLE; - HME_MAC_WRITE_4(sc, HME_MACI_XIF, v); } static int ==== //depot/projects/sparc64/sys/dev/hme/if_hme_pci.c#11 (text+ko) ==== @@ -151,7 +151,7 @@ } hsc->hsc_irid = 0; hsc->hsc_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &hsc->hsc_irid, 0, - ~0, 1, RF_ACTIVE); + ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (hsc->hsc_ires == NULL) { device_printf(dev, "could not allocate interrupt\n"); error = ENXIO; ==== //depot/projects/sparc64/sys/dev/hme/if_hme_sbus.c#5 (text+ko) ==== @@ -222,7 +222,7 @@ hsc->hsc_irid = 0; hsc->hsc_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &hsc->hsc_irid, 0, - ~0, 1, RF_ACTIVE); + ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (hsc->hsc_ires == NULL) { device_printf(dev, "could not allocate interrupt\n"); error = ENXIO; ==== //depot/projects/sparc64/sys/dev/hme/if_hmevar.h#9 (text+ko) ==== @@ -50,7 +50,7 @@ * memory is sizeof(struct hme_txdesc)). * Both must be a multiple of 16, and <= 128. */ -#define HME_NRXDESC 32 +#define HME_NRXDESC 64 #define HME_NTXDESC 64 /* Maximum size of a mapped RX buffer. */ ==== //depot/projects/sparc64/sys/sparc64/ebus/ebus.c#9 (text+ko) ==== @@ -54,13 +54,13 @@ #include #include +#include +#include + #include #include #include -#include -#include - #include #include @@ -99,18 +99,7 @@ struct isa_ranges *sc_range; - struct ofw_pci_register *sc_reg; - - int sc_imap_type; - - struct isa_imap *sc_ebus_imap; - struct isa_imap_msk sc_ebus_imapmsk; - - struct ofw_pci_imap *sc_pci_imap; - struct ofw_pci_imap_msk sc_pci_imapmsk; - int sc_nrange; - int sc_nreg; int sc_nimap; }; @@ -127,7 +116,6 @@ phandle_t, char *); static void ebus_destroy_dinfo(struct ebus_devinfo *); static int ebus_print_res(struct ebus_devinfo *); -static int ebus_map_intr(struct ebus_softc *, int, struct isa_regs *, int); static device_method_t ebus_methods[] = { /* Device interface */ @@ -199,42 +187,10 @@ sc = device_get_softc(dev); sc->sc_node = node; - /* - * Fill in our softc with information from the prom. - * There are two possible cases how interrupt mapping needs to be - * handled: - * - if the ebus node has an interrupt-map properties, the interrut - * numbers in child nodes can be mapped using lookups in this map, - * using the registers of the child node in question to find the - * map entry - * - if it does not have such a properties, the interrupts are mapped - * in the next higher interrupt map (PCI in our case), using the - * interrupt number of the child, but the registers of the ebus - * node, to find the mapping. - */ - sc->sc_imap_type = EBUS_IT_EBUS; - sc->sc_nimap = OF_getprop_alloc(node, "interrupt-map", - sizeof(*sc->sc_ebus_imap), (void **)&sc->sc_ebus_imap); - if (sc->sc_nimap == -1) { - sc->sc_nimap = ofw_pci_find_imap(node, &sc->sc_pci_imap, - &sc->sc_pci_imapmsk); - if (sc->sc_nimap == -1) - panic("ebus_probe: no interrupt map found"); - sc->sc_imap_type = EBUS_IT_PCI; - } else { - if (OF_getprop(node, "interrupt-map-mask", - &sc->sc_ebus_imapmsk, sizeof(sc->sc_ebus_imapmsk)) == -1) { - panic("ebus_probe: could not get ebus " - "interrupt-map-mask"); - } - } - sc->sc_nrange = OF_getprop_alloc(node, "ranges", sizeof(*sc->sc_range), (void **)&sc->sc_range); - sc->sc_nreg = OF_getprop_alloc(node, "reg", - sizeof(*sc->sc_reg), (void **)&sc->sc_reg); - if (sc->sc_nrange == -1 || sc->sc_nreg == -1) - panic("ebus_attach: could not get ranges/reg property"); + if (sc->sc_nrange == -1) + panic("ebus_attach: could not get ranges property"); /* * now attach all our children @@ -411,9 +367,9 @@ { struct ebus_devinfo *edi; struct isa_regs *reg; - u_int32_t *intrs; + u_int32_t *intrs, intr; u_int64_t start; - int nreg, nintr, i, intr; + int nreg, nintr, i; edi = malloc(sizeof(*edi), M_DEVBUF, M_ZERO | M_WAITOK); if (edi == NULL) @@ -442,10 +398,11 @@ nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intrs), (void **)&intrs); for (i = 0; i < nintr; i++) { - intr = ebus_map_intr(sc, intrs[i], reg, nreg); - if (intr == -1) + intr = ofw_bus_route_intr(node, intrs[i]); + if (intr == ORIR_NOTFOUND) { panic("ebus_setup_dinfo: could not map ebus " "interrupt %d", intrs[i]); + } resource_list_add(&edi->edi_rl, SYS_RES_IRQ, i, intr, intr, 1); } @@ -479,20 +436,3 @@ "%ld"); return (retval); } - -static int -ebus_map_intr(struct ebus_softc *sc, int intr, struct isa_regs *regs, - int nregs) -{ - int rv; - - if (sc->sc_imap_type == EBUS_IT_PCI) { - rv = ofw_pci_route_intr2(intr, sc->sc_reg, sc->sc_pci_imap, - sc->sc_nimap, &sc->sc_pci_imapmsk); - if (rv == 255) - return (-1); - return (rv); - } - return (ofw_isa_map_intr(sc->sc_ebus_imap, sc->sc_nimap, - &sc->sc_ebus_imapmsk, intr, regs, nregs)); -} ==== //depot/projects/sparc64/sys/sparc64/ebus/ebusvar.h#4 (text+ko) ==== @@ -35,17 +35,6 @@ #ifndef _SPARC64_EBUS_EBUSVAR_H_ #define _SPARC64_EBUS_EBUSVAR_H_ -/* - * Interrupt map type (for the sc_imap_type softc member): - * If the ebus node has an interrupt map, this is set to EBUS_IT_EBUS (and the - * relevant sotfc members are initialized with the EBUS types), otherwise, - * it is EBUS_IT_PCI, in which case the standard PCI functions are used to - * map the interrupt (this is needed because the the maps and masks are - * different). - */ -#define EBUS_IT_EBUS 1 -#define EBUS_IT_PCI 2 - enum ebus_device_ivars { EBUS_IVAR_COMPAT, EBUS_IVAR_NAME, ==== //depot/projects/sparc64/sys/sparc64/include/ofw_bus.h#5 (text+ko) ==== @@ -28,7 +28,9 @@ #ifndef _MACHINE_OFW_BUS_H_ #define _MACHINE_OFW_BUS_H_ -u_int32_t ofw_bus_route_intr(int intr, void *regs, int regsz, int physz, - int nregs, void *imap, int nimap, void *imapmsk, char *regm); +#define ORIP_NOINT -1 +#define ORIR_NOTFOUND 0xffffffff + +u_int32_t ofw_bus_route_intr(phandle_t, int); #endif /* !_MACHINE_OFW_BUS_H_ */ ==== //depot/projects/sparc64/sys/sparc64/isa/isa.c#8 (text+ko) ==== @@ -51,6 +51,7 @@ #include #include +#include #include #include @@ -71,11 +72,8 @@ device_t isa_bus_device; -static struct ofw_pci_register isab_reg; -static struct ofw_pci_imap *isab_imap; -static int isab_nimap; -static struct ofw_pci_imap_msk isab_imap_msk; static phandle_t isab_node; +static u_int32_t isa_ino[8]; /* * XXX: This is really partly partly PCI-specific, but unfortunately is @@ -92,8 +90,6 @@ static int isa_route_intr_res(device_t, u_long, u_long); -static int isa_ino[8]; - intrmask_t isa_irq_pending(void) { @@ -103,7 +99,7 @@ /* XXX: Is this correct? */ for (i = 7, pending = 0; i >= 0; i--) { pending <<= 1; - if (isa_ino[i] != 255) { + if (isa_ino[i] != ORIR_NOTFOUND) { pending |= (SPARCBUS_INTR_PENDING(isa_bus_device, isa_ino[i]) == 0) ? 0 : 1; } @@ -116,28 +112,30 @@ { device_t bridge; phandle_t node; + u_int32_t ino; struct isa_ranges *br; int nbr, i; /* The parent of the bus must be a PCI-ISA bridge. */ bridge = device_get_parent(dev); - isab_node = ofw_pci_find_node(pci_get_bus(bridge), pci_get_slot(bridge), - pci_get_function(bridge)); - if (OF_getprop(isab_node, "reg", &isab_reg, sizeof(isab_reg)) < 0) - panic("isa_init: cannot get bridge reg property"); + isab_node = ofw_pci_node(bridge); nbr = OF_getprop_alloc(isab_node, "ranges", sizeof(*br), (void **)&br); if (nbr <= 0) panic("isa_init: cannot get bridge range property"); - node = isab_node; - isab_nimap = ofw_pci_find_imap(node, &isab_imap, &isab_imap_msk); - if (isab_nimap == -1) - panic("isa_init: could not find interrupt-map"); - for (i = 0; i < 8; i++) { - isa_ino[i] = ofw_pci_route_intr2(i, &isab_reg, isab_imap, - isab_nimap, &isab_imap_msk); + /* + * This is really a bad kluge; however, it is needed to provide + * isa_irq_pending(). + */ + for (i = 0; i < 8; i++) + isa_ino[i] = ORIR_NOTFOUND; + for (node = OF_child(isab_node); node != 0; node = OF_peer(node)) { + if (OF_getprop(node, "interrupts", &ino, sizeof(ino)) == -1) + continue; + if (ino > 7) + panic("isa_init: XXX: ino too large"); + isa_ino[ino] = ofw_bus_route_intr(node, ino); } - for (nbr -= 1; nbr >= 0; nbr--) { switch(ISAB_RANGE_SPACE(br + nbr)) { case ISAR_SPACE_IO: @@ -168,8 +166,9 @@ panic("isa_route_intr_res: allocation of interrupt range not " "supported (0x%lx - 0x%lx)", start, end); } - res = ofw_pci_route_intr2(start, &isab_reg, isab_imap, isab_nimap, - &isab_imap_msk); + if (start > 7) + panic("isa_route_intr_res: start out of isa range"); + res = isa_ino[start]; if (res == 255) device_printf(bus, "could not map interrupt %d\n", res); return (res); ==== //depot/projects/sparc64/sys/sparc64/isa/ofw_isa.c#7 (text+ko) ==== @@ -48,19 +48,6 @@ #include #include -/* - * This applies only for an ISA/EBus with an own interrupt-map property. - */ -int -ofw_isa_map_intr(struct isa_imap *imap, int nimap, struct isa_imap_msk *imapmsk, - int intr, struct isa_regs *regs, int nregs) -{ - char regm[8]; - - return (ofw_bus_route_intr(intr, regs, sizeof(*regs), 8, nregs, - imap, nimap, imapmsk, regm)); -} - /* XXX: this only supports PCI as parent bus right now. */ int ofw_isa_map_iorange(struct isa_ranges *range, int nrange, u_long *start, ==== //depot/projects/sparc64/sys/sparc64/pci/apb.c#8 (text+ko) ==== @@ -46,8 +46,13 @@ #include #include +#include +#include + #include +#include + #include #include @@ -343,12 +348,27 @@ } /* - * Route an interrupt across a PCI bridge - the APB does not route interrupts, - * and routing of interrupts that are not preinitialized is not supported yet. + * Route an interrupt across a PCI bridge - we need to rely on the firmware + * here. */ static int apb_route_interrupt(device_t pcib, device_t dev, int pin) { - panic("apb_route_interrupt"); + /* + * XXX: ugly loathsome hack: + * We can't use ofw_pci_route_intr() here; the device passed may be + * the one of a bridge, so the original device can't be recovered. + * + * We need to use the firmware to route interrupts, however it has + * no interface which could be used to interpret intpins; instead, + * all assignments are done by device. + * + * The MI pci code will try to reroute interrupts of 0, although they + * are correct; all other interrupts are preinitialized, so if we + * get here, the intline is either 0 (so return 0), or we hit a + * device which was not preinitialized (e.g. hotplugged stuff), in + * which case we are lost. + */ + return (0); } ==== //depot/projects/sparc64/sys/sparc64/pci/ofw_pci.c#7 (text+ko) ==== @@ -50,66 +50,15 @@ #include "pcib_if.h" -/* - * Find the interrupt-map properties for a node. This might not be a property - * of the parent, because there may be bridges in between, so go up through the - * tree to find it. - * This seems to be only needed for PCI systems, so it has not been moved to - * ofw_bus.c - */ -int -ofw_pci_find_imap(phandle_t node, struct ofw_pci_imap **imap, - struct ofw_pci_imap_msk *imapmsk) +u_int32_t +ofw_pci_route_intr(phandle_t node) { - int nimap; + u_int32_t rv; - nimap = -1; - while ((node = OF_parent(node)) != 0) { - if ((nimap = OF_getprop_alloc(node, "interrupt-map", - sizeof(**imap), (void **)imap)) == -1 || - OF_getprop(node, "interrupt-map-mask", - imapmsk, sizeof(*imapmsk)) == -1) { - if (*imap != NULL) { - free(*imap, M_OFWPROP); - *imap = NULL; - } - nimap = -1; - } else - break; - } - return (nimap); -} - -/* - * Route an interrupt using the firmware nodes. Returns 255 for interrupts - * that cannot be routed (suitable for the PCI code). - */ -int -ofw_pci_route_intr2(int intr, struct ofw_pci_register *pcir, - struct ofw_pci_imap *imap, int nimap, struct ofw_pci_imap_msk *imapmsk) -{ - char regm[12]; - int cintr; - - cintr = ofw_bus_route_intr(intr, pcir, sizeof(*pcir), 12, 1, imap, - nimap, imapmsk, regm); - if (cintr == -1) + rv = ofw_bus_route_intr(node, ORIP_NOINT); + if (rv == ORIR_NOTFOUND) return (255); - else - return (cintr); -} - -int -ofw_pci_route_intr(phandle_t node, struct ofw_pci_register *pcir, - struct ofw_pci_imap *intrmap, int nintrmap, - struct ofw_pci_imap_msk *intrmapmsk) -{ - int intr; - - if (OF_getprop(node, "interrupts", &intr, sizeof(intr)) == -1) - return (255); - - return (ofw_pci_route_intr2(intr, pcir, intrmap, nintrmap, intrmapmsk)); + return (rv); } #define OFW_PCI_PCIBUS "pci" @@ -119,10 +68,8 @@ * of attached devices using firmware information. */ void -ofw_pci_init_intr(device_t dev, phandle_t bus, struct ofw_pci_imap *intrmap, - int nintrmap, struct ofw_pci_imap_msk *intrmapmsk) +ofw_pci_init_intr(device_t dev, phandle_t bus) { - struct ofw_pci_imap_msk lintrmapmsk; struct ofw_pci_register pcir; phandle_t node; char type[32]; @@ -146,40 +93,19 @@ * deep, so recursion is feasible. */ #ifdef OFW_PCI_DEBUG - device_printf(dev, __func__": descending to " - "subordinate PCI bus\n"); + device_printf(dev, "%s: descending to " + "subordinate PCI bus\n", __func__); #endif - ofw_pci_init_intr(dev, node, NULL, 0, NULL); + ofw_pci_init_intr(dev, node); } else { if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) panic("ofw_pci_route_intr: OF_getprop failed"); - /* - * If we didn't get interrupt map properties passed, - * try to find them now. On some systems, buses that - * have no non-bridge children have no such properties, - * so only try to find them at need. - */ - if (intrmap == NULL) { - nintrmap = OF_getprop_alloc(bus, - "interrupt-map", sizeof(*intrmap), - (void **)&intrmap); - if (nintrmap == -1 || - OF_getprop(bus, "interrupt-map-mask", - &lintrmapmsk, sizeof(lintrmapmsk)) == -1) { - printf("ofw_pci_init_intr: could not get " - "interrupt map properties\n"); - if (nintrmap != -1) - free(intrmap, M_OFWPROP); - return; - } - intrmapmsk = &lintrmapmsk; - freemap = 1; - } - if ((intr = ofw_pci_route_intr(node, &pcir, intrmap, - nintrmap, intrmapmsk)) != 255) { + + if ((intr = ofw_pci_route_intr(node)) != 255) { #ifdef OFW_PCI_DEBUG - device_printf(dev, __func__": mapping intr for " + device_printf(dev, "%s: mapping intr for " "%d/%d/%d to %d (preset was %d)\n", + __func__, OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), @@ -189,7 +115,6 @@ OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), PCIR_INTLINE, 1)); - #endif /* OFW_PCI_DEBUG */ PCIB_WRITE_CONFIG(dev, OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), @@ -198,8 +123,9 @@ PCIR_INTLINE, intr, 1); } else { #ifdef OFW_PCI_DEBUG - device_printf(dev, __func__": no interrupt " + device_printf(dev, "%s: no interrupt " "mapping found for %d/%d/%d (preset %d)\n", + __func__, OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), @@ -218,8 +144,6 @@ } } } while ((node = OF_peer(node)) != 0); - if (freemap) - free(intrmap, M_OFWPROP); } phandle_t @@ -268,3 +192,11 @@ } return (0); } + +phandle_t +ofw_pci_node(device_t dev) +{ + + return (ofw_pci_find_node(pci_get_bus(dev), pci_get_slot(dev), + pci_get_function(dev))); +} ==== //depot/projects/sparc64/sys/sparc64/pci/ofw_pci.h#4 (text+ko) ==== @@ -56,18 +56,9 @@ u_int32_t intr; }; -int ofw_pci_find_imap(phandle_t, struct ofw_pci_imap **, - struct ofw_pci_imap_msk *); -int ofw_pci_route_intr2(int, struct ofw_pci_register *, - struct ofw_pci_imap *, int, struct ofw_pci_imap_msk *); -int ofw_pci_route_intr(phandle_t, struct ofw_pci_register *, - struct ofw_pci_imap *, int, struct ofw_pci_imap_msk *); -void ofw_pci_init_intr(device_t, phandle_t, struct ofw_pci_imap *, int, - struct ofw_pci_imap_msk *); +u_int32_t ofw_pci_route_intr(phandle_t); +void ofw_pci_init_intr(device_t, phandle_t); phandle_t ofw_pci_find_node(int, int, int); -int ofw_pci_dev_iterate_node(device_t, phandle_t, uintptr_t *, int, int *, - int *, uintptr_t *, uintptr_t *); -int ofw_pci_dev_iterate(device_t, uintptr_t *, int, int *, int *, uintptr_t *, - uintptr_t *); +phandle_t ofw_pci_node(device_t); #endif /* ! _SPARC64_PCI_OFW_PCI_H_ */ ==== //depot/projects/sparc64/sys/sparc64/pci/psycho.c#24 (text+ko) ==== @@ -478,16 +478,6 @@ /* XXX: register as root dma tag (kluge). */ sparc64_root_dma_tag = sc->sc_dmat; - if ((sc->sc_nintrmap = OF_getprop_alloc(sc->sc_node, "interrupt-map", - sizeof(*sc->sc_intrmap), (void **)&sc->sc_intrmap)) == -1 || - OF_getprop(sc->sc_node, "interrupt-map-mask", &sc->sc_intrmapmsk, - sizeof(sc->sc_intrmapmsk)) == -1) { - if (sc->sc_intrmap != NULL) { - free(sc->sc_intrmap, M_OFWPROP); - sc->sc_intrmap = NULL; - } - } - /* Register the softc, this is needed for paired psychos. */ if (psycho_ndevs < sizeof(psycho_softcs) / sizeof(psycho_softcs[0])) psycho_softcs[psycho_ndevs] = sc; @@ -617,8 +607,7 @@ * at least on some models, and we probably shouldn't trust that * the firmware uses the same model as this driver if it does. */ - ofw_pci_init_intr(dev, sc->sc_node, sc->sc_intrmap, sc->sc_nintrmap, - &sc->sc_intrmapmsk); + ofw_pci_init_intr(dev, sc->sc_node); device_add_child(dev, "pci", device_get_unit(dev)); return (bus_generic_attach(dev)); @@ -969,18 +958,21 @@ int intline; /* - * Since we preinitialize all interrupt line registers, this should not - * happen for any built-in device, except it the intline is 0. - * For now, just ignore this case - 0 is a valid intline on sparc64, - * but due to quirky BIOSes the PCI code attempts to route anyway. - * If it is 255, we are lost for now. - * Devices on bridges that route interrupts cannot work now - the - * interrupt pin mappings cannot be obtained from the firmware... + * XXX: ugly loathsome hack: + * We can't use ofw_pci_route_intr() here; the device passed may be + * the one of a bridge, so the original device can't be recovered. + * + * We need to use the firmware to route interrupts, however it has + * no interface which could be used to interpret intpins; instead, + * all assignments are done by device. + * + * The MI pci code will try to reroute interrupts of 0, although they + * are correct; all other interrupts are preinitialized, so if we + * get here, the intline is either 0 (so return 0), or we hit a + * device which was not preinitialized (e.g. hotplugged stuff), in + * which case we are lost. */ - intline = pci_read_config(dev, PCIR_INTLINE, 1); - if (intline == 255) - panic("psycho_route_interrupt: can't get interrupt"); - return (intline); + return (0); } static int ==== //depot/projects/sparc64/sys/sparc64/pci/psychovar.h#9 (text+ko) ==== @@ -74,9 +74,6 @@ */ struct upa_ranges *sc_range; int sc_nrange; - struct ofw_pci_imap *sc_intrmap; - int sc_nintrmap; - struct ofw_pci_imap_msk sc_intrmapmsk; /* our tags */ bus_space_tag_t sc_cfgt; ==== //depot/projects/sparc64/sys/sparc64/sparc64/iommu.c#17 (text+ko) ==== @@ -246,7 +246,7 @@ * Now all the hardware's working we need to setup dvma resource * management. */ - printf("DVMA map: %lx to %lx\n", + printf("DVMA map: %#lx to %#lx\n", is->is_dvmabase, is->is_dvmabase + (size << (IO_PAGE_SHIFT - IOTTE_SHIFT)) - 1); ==== //depot/projects/sparc64/sys/sparc64/sparc64/ofw_bus.c#5 (text+ko) ==== @@ -1,3 +1,33 @@ +/* + * Copyright (C) 1996 Wolfgang Solfrank. + * Copyright (C) 1996 TooLs GmbH. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /*- * Copyright (c) 2001 by Thomas Moestl . * All rights reserved. @@ -22,6 +52,8 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * from: $NetBSD: ofw_machdep.c,v 1.16 2001/07/20 00:07:14 eeh Exp $ + * * $FreeBSD: src/sys/sparc64/sparc64/ofw_bus.c,v 1.1 2001/11/09 20:10:55 tmm Exp $ */ @@ -40,51 +72,169 @@ #include +/* + * Other than in OpenFirmware calls, the size of a bus cell seems to be always + * the same. + */ +typedef u_int32_t pcell_t; + +static int +ofw_bus_searchprop(phandle_t node, char *propname, void *buf, int buflen) +{ + int rv; + + for (; node != 0; node = OF_parent(node)) { + if ((rv = OF_getprop(node, propname, buf, buflen)) != -1) + return (rv); + } + return (-1); +} + /* - * Route an interrupt using the firmware. This takes an interrupt map and mask, - * as retrieved from the firmware (this must be done by the caller, since it - * is not bus-independent). - * regs points to a "reg" property as returned by the firmware. regsz ist the - * the size of one reg element, physz is the size of the physical address member - * at the start of each reg (this is matched against the interrupt map). - * The interrupt map has entries of the size (physsz + 12), the 12 being the - * size of two u_int32_t that hold the interrupt number to compare against, the - * node the map belongs to and the interrupt that the child interrupt is mapped - * to (if the map entry matches). - * The first nregs registers are checked against the map; in some cases (e.g. - * PCI), only the first must be checked. - * The mask consists of a mask wich must be and-ed to the checked physical - * address part of the ofw reg and to the interrupt number before checking - * against the map. - * regm should point to a buffer of physsz size (this is not malloc'ed because - * malloc cannot be called in all situations). + * Map an interrupt using the firmware reg, interrupt-map and + * interrupt-map-mask properties. + * The interrupt is returned in *result, which is malloc()'ed. The size of + * the interrupt specifiaction is returned. */ -u_int32_t -ofw_bus_route_intr(int intr, void *regs, int regsz, int physsz, int nregs, - void *imap, int nimap, void *imapmsk, char *regm) +static int +ofw_bus_find_intr(u_int8_t *intr, int intrsz, u_int8_t *regs, int physsz, + u_int8_t *imap, int imapsz, u_int8_t *imapmsk, u_int8_t **result) { + phandle_t parent; + char *ref; u_int8_t *mptr; - u_int32_t mintr, cintr; - int r, i; + pcell_t pintrsz; + int i, rsz, tsz; - cintr = -1; - bcopy((u_int8_t *)imapmsk + physsz, &mintr, sizeof(mintr)); - mintr &= intr; - for (r = 0; r < nregs; r++) { - for (i = 0; i < physsz; i++) { - regm[i] = ((u_int8_t *)regs)[r * regsz + i] & - ((u_int8_t *)imapmsk)[i]; + rsz = -1; + ref = malloc(physsz + intrsz, M_TEMP, M_WAITOK); + if (imapmsk != NULL) { + for (i = 0; i < physsz; i++) + ref[i] = regs[i] & imapmsk[i]; + for (i = 0; i < intrsz; i++) + ref[physsz + i] = intr[i] & imapmsk[physsz + i]; + } else { + bcopy(regs, ref, physsz); + bcopy(intr, ref + physsz, intrsz); + } + mptr = imap; + i = imapsz; + while (i > 0) { + KASSERT(i >= physsz + sizeof(parent), + ("ofw_bus_find_intr: truncated map")); + bcopy(mptr + physsz + intrsz, &parent, sizeof(parent)); + if (ofw_bus_searchprop(parent, "#interrupt-cells", + &pintrsz, sizeof(pintrsz)) == -1) + pintrsz = 1; /* default */ + pintrsz *= sizeof(pcell_t); + KASSERT(i >= physsz + intrsz + sizeof(parent) + + pintrsz, ("ofw_bus_find_intr: truncated map")); + if (bcmp(ref, mptr, physsz + intrsz) == 0) { + *result = malloc(pintrsz, M_OFWPROP, M_WAITOK); + bcopy(mptr + physsz + intrsz + sizeof(parent), + *result, pintrsz); + rsz = pintrsz; + break; } - for (i = 0; i < nimap; i++) { - mptr = (u_int8_t *)imap + i * (physsz + 12); - if (bcmp(regm, mptr, physsz) == 0 && - bcmp(&mintr, mptr + physsz, sizeof(mintr)) == 0) { - bcopy(mptr + physsz + 8, &cintr, - sizeof(cintr)); - break; - } + tsz = physsz + intrsz + sizeof(phandle_t) + pintrsz; + mptr += tsz; + i -= tsz; + } + free(ref, M_TEMP); + return (rsz); +} + +/* + * Apply the OpenFirmware algorithm for mapping an interrupt. First, the + * 'interrupts' and 'reg' properties are retrieved; those are matched against + * the interrupt map of the next higher node. If there is no match or no such + * propery, we go to the next higher node, using the 'reg' property of the node + * that was just processed unusccessfully. + * When a match occurs, we continue to search, using the new interrupt + * specification that was just found. + * When the root node is reached with at least one successful mapping performed, + * and the format is right, the interrupt number is returned. + * + * This should work for all bus systems. + */ +u_int32_t +ofw_bus_route_intr(phandle_t node, int intrp) +{ + u_int8_t *reg, *intr, *tintr, *imap, *imapmsk; + phandle_t parent; + pcell_t addrc, ic; + u_int32_t rv; + int regsz, tisz, isz, imapsz, found; + + found = 0; + reg = imap = imapmsk = NULL; + if (intrp == ORIP_NOINT) { + isz = OF_getprop_alloc(node, "interrupts", 1, (void **)&intr); + if (isz < 0) + return (ORIR_NOTFOUND); + } else { + ic = intrp; + isz = sizeof(ic); + intr = malloc(isz, M_OFWPROP, M_WAITOK); + bcopy(&ic, intr, isz); + } + /* + * Note that apparently, remapping at multiple levels is allowed; + * however, this causes problems with EBus at least, and seems to never + * be needed, so we disable it for now (*sigh*). + */ + for (parent = OF_parent(node); parent != 0 && !found; + parent = OF_parent(node = parent)) { + if (reg != NULL) + free(reg, M_OFWPROP); + regsz = OF_getprop_alloc(node, "reg", 1, (void **)®); + if (regsz < 0) + panic("ofw_bus_route_intr: could not get reg property"); + imapsz = OF_getprop_alloc(parent, "interrupt-map", 1, + (void **)&imap); + if (imapsz == -1) + continue; + if (OF_getprop(parent, "#address-cells", &addrc, + sizeof(addrc)) == -1) + addrc = 2; + addrc *= sizeof(pcell_t); + /* + * Failures to get the mask are ignored; a full mask is assumed + * in this case. + */ + OF_getprop_alloc(parent, "interrupt-map-mask", 1, + (void **)&imapmsk); + tisz = ofw_bus_find_intr(intr, isz, reg, addrc, imap, imapsz, + imapmsk, &tintr); + if (tisz != -1) { + found = 1; + isz = tisz; + free(intr, M_OFWPROP); + intr = tintr; } + free(imap, M_OFWPROP); + if (imapmsk != NULL) + free(imapmsk, M_OFWPROP); + } + if (reg != NULL) + free(reg, M_OFWPROP); +#if 0 + /* + * Obviously there are some boxes that don't require mapping at all, + * for example the U30, which has no interrupt maps for children of + * the root PCI bus. + */ + if (!found) { + if (intrp != ORIP_NOINT) + return (ORIR_NOTFOUND); + panic("ofw_bus_route_intr: 'interrupts' property, but no " + "mapping found"); } - return (cintr); +#endif + KASSERT(isz == sizeof(u_int32_t), + ("ofw_bus_route_intr: bad interrupt spec size %d", isz)); + bcopy(intr, &rv, sizeof(rv)); + free(intr, M_OFWPROP); + return (rv); } To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe p4-projects" in the body of the message