Index: ebus/ebus.c =================================================================== RCS file: /space/ncvs/src/sys/sparc64/ebus/ebus.c,v retrieving revision 1.4 diff -u -r1.4 ebus.c --- ebus/ebus.c 24 Mar 2002 02:11:06 -0000 1.4 +++ ebus/ebus.c 6 Nov 2002 23:20:54 -0000 @@ -398,7 +398,7 @@ nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intrs), (void **)&intrs); for (i = 0; i < nintr; i++) { - intr = ofw_bus_route_intr(node, intrs[i]); + intr = ofw_bus_route_intr(node, intrs[i], ofw_pci_orb_callback); if (intr == ORIR_NOTFOUND) { panic("ebus_setup_dinfo: could not map ebus " "interrupt %d", intrs[i]); Index: include/ofw_bus.h =================================================================== RCS file: /space/ncvs/src/sys/sparc64/include/ofw_bus.h,v retrieving revision 1.2 diff -u -r1.2 ofw_bus.h --- include/ofw_bus.h 24 Mar 2002 02:11:00 -0000 1.2 +++ include/ofw_bus.h 6 Nov 2002 23:20:54 -0000 @@ -31,6 +31,9 @@ #define ORIP_NOINT -1 #define ORIR_NOTFOUND 0xffffffff -u_int32_t ofw_bus_route_intr(phandle_t, int); +typedef int obr_callback_t(phandle_t, u_int8_t *, int, u_int8_t *, int, + u_int8_t **, int *); + +u_int32_t ofw_bus_route_intr(phandle_t, int, obr_callback_t *); #endif /* !_MACHINE_OFW_BUS_H_ */ Index: include/ver.h =================================================================== RCS file: /space/ncvs/src/sys/sparc64/include/ver.h,v retrieving revision 1.3 diff -u -r1.3 ver.h --- include/ver.h 13 Jul 2002 03:23:29 -0000 1.3 +++ include/ver.h 6 Nov 2002 23:20:54 -0000 @@ -59,6 +59,7 @@ (((ver) & VER_MAXWIN_MASK) >> VER_MAXWIN_SHIFT) extern int cpu_impl; +extern char sparc64_model[]; /* Known implementations. */ #define CPU_IMPL_SPARC64 0x01 Index: isa/isa.c =================================================================== RCS file: /space/ncvs/src/sys/sparc64/isa/isa.c,v retrieving revision 1.4 diff -u -r1.4 isa.c --- isa/isa.c 2 Apr 2002 17:23:45 -0000 1.4 +++ isa/isa.c 6 Nov 2002 23:20:54 -0000 @@ -133,7 +133,8 @@ continue; if (ino > 7) panic("isa_init: XXX: ino too large"); - isa_ino[ino] = ofw_bus_route_intr(node, ino); + isa_ino[ino] = ofw_bus_route_intr(node, ino, + ofw_pci_orb_callback); } for (nbr -= 1; nbr >= 0; nbr--) { Index: pci/ofw_pci.c =================================================================== RCS file: /space/ncvs/src/sys/sparc64/pci/ofw_pci.c,v retrieving revision 1.4 diff -u -r1.4 ofw_pci.c --- pci/ofw_pci.c 12 Jun 2002 19:20:57 -0000 1.4 +++ pci/ofw_pci.c 7 Nov 2002 00:07:55 -0000 @@ -47,6 +47,7 @@ #include #include +#include #include "pcib_if.h" @@ -54,16 +55,63 @@ phandle_t *pci_bus_map; int pci_bus_map_sz; +#define OPQ_NEED_SWIZZLE 1 +static struct ofw_pci_quirk { + char *opq_model; + int opq_quirks; +} ofw_pci_quirks[] = { + { "SUNW,UltraSPARC-IIi-cEngine", OPQ_NEED_SWIZZLE } +}; +#define OPQ_NENT (sizeof(ofw_pci_quirks) / sizeof(ofw_pci_quirks[0])) + +static int pci_quirks; + +#define OFW_PCI_PCIBUS "pci" #define PCI_BUS_MAP_INC 10 +int +ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz, + u_int8_t *pregptr, int pregsz, u_int8_t **rintr, int *terminate) +{ + struct ofw_pci_register preg; + u_int32_t pintr, intr; + char type[32]; + + if ((pci_quirks & OPQ_NEED_SWIZZLE) != 0 && + pintsz == sizeof(u_int32_t) && pregsz >= sizeof(preg) && + OF_getprop(node, "device_type", type, sizeof(type)) != -1 && + strcmp(type, OFW_PCI_PCIBUS) == 0) { + /* + * Handle a quirk found on some Netra t1 models: there exist + * PCI bridges without interrupt maps, where we apparently must + * do the PCI swizzle and continue to map on at the parent. + */ + bcopy(pintptr, &pintr, sizeof(pintr)); + bcopy(pregptr, &preg, sizeof(preg)); + intr = (OFW_PCI_PHYS_HI_DEVICE(preg.phys_hi) + pintr) % 4; + *rintr = malloc(sizeof(intr), M_OFWPROP, M_WAITOK); + bcopy(&intr, *rintr, sizeof(intr)); + *terminate = 0; + return (sizeof(intr)); + } + return (-1); +} + u_int32_t -ofw_pci_route_intr(phandle_t node) +ofw_pci_route_intr(phandle_t node, u_int32_t ign) { u_int32_t rv; - rv = ofw_bus_route_intr(node, ORIP_NOINT); + rv = ofw_bus_route_intr(node, ORIP_NOINT, ofw_pci_orb_callback); if (rv == ORIR_NOTFOUND) return (255); + /* + * Some machines (notably the SPARCengine Ultra AX) have no mappings + * at all, but use complete interrupt vector number including the IGN. + * Catch this case and remove the IGN. + */ + if (rv > ign) + rv -= ign; return (rv); } @@ -112,7 +160,6 @@ PCIR_SUBBUS_1, obd->obd_subbus, 1); } -#define OFW_PCI_PCIBUS "pci" /* * Walk the PCI bus hierarchy, starting with the root PCI bus and descending * through bridges, and initialize the interrupt line and latency timer @@ -120,15 +167,24 @@ * as well as the the bus numbers and ranges of the bridges. */ void -ofw_pci_init(device_t dev, phandle_t bushdl, struct ofw_pci_bdesc *obd) +ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign, + struct ofw_pci_bdesc *obd) { struct ofw_pci_register pcir; struct ofw_pci_bdesc subobd, *tobd; phandle_t node; char type[32]; - int intr, freemap; + int i, intr, freemap; u_int slot, busno, func, sub, lat; + /* Initialize the quirk list. */ + for (i = 0; i < OPQ_NENT; i++) { + if (strcmp(sparc64_model, ofw_pci_quirks[i].opq_model) == 0) { + pci_quirks = ofw_pci_quirks[i].opq_quirks; + break; + } + } + if ((node = OF_child(bushdl)) == 0) return; freemap = 0; @@ -141,7 +197,7 @@ else type[sizeof(type) - 1] = '\0'; if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) - panic("ofw_pci_route_intr: OF_getprop failed"); + panic("ofw_pci_init: OF_getprop failed"); slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi); func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi); if (strcmp(type, OFW_PCI_PCIBUS) == 0) { @@ -173,7 +229,7 @@ device_printf(dev, "%s: descending to " "subordinate PCI bus\n", __func__); #endif /* OFW_PCI_DEBUG */ - ofw_pci_init(dev, node, &subobd); + ofw_pci_init(dev, node, ign, &subobd); } else { /* * Initialize the latency timer register for @@ -199,7 +255,7 @@ } /* Initialize the intline registers. */ - if ((intr = ofw_pci_route_intr(node)) != 255) { + if ((intr = ofw_pci_route_intr(node, ign)) != 255) { #ifdef OFW_PCI_DEBUG device_printf(dev, "%s: mapping intr for " "%d/%d/%d to %d (preset was %d)\n", Index: pci/ofw_pci.h =================================================================== RCS file: /space/ncvs/src/sys/sparc64/pci/ofw_pci.h,v retrieving revision 1.3 diff -u -r1.3 ofw_pci.h --- pci/ofw_pci.h 12 Jun 2002 19:20:57 -0000 1.3 +++ pci/ofw_pci.h 6 Nov 2002 23:20:54 -0000 @@ -34,6 +34,8 @@ #ifndef _SPARC64_PCI_OFW_PCI_H_ #define _SPARC64_PCI_OFW_PCI_H_ +#include + /* PCI range child spaces. XXX: are these MI? */ #define PCI_CS_CONFIG 0x00 #define PCI_CS_IO 0x01 @@ -69,10 +71,11 @@ struct ofw_pci_bdesc *obd_super; }; -u_int32_t ofw_pci_route_intr(phandle_t); +u_int32_t ofw_pci_route_intr(phandle_t, u_int32_t); +obr_callback_t ofw_pci_orb_callback; u_int8_t ofw_pci_alloc_busno(phandle_t); ofw_pci_binit_t ofw_pci_binit; -void ofw_pci_init(device_t, phandle_t, struct ofw_pci_bdesc *); +void ofw_pci_init(device_t, phandle_t, u_int32_t, struct ofw_pci_bdesc *); phandle_t ofw_pci_find_node(int, int, int); phandle_t ofw_pci_node(device_t); Index: pci/psycho.c =================================================================== RCS file: /space/ncvs/src/sys/sparc64/pci/psycho.c,v retrieving revision 1.16 diff -u -r1.16 psycho.c --- pci/psycho.c 16 Oct 2002 17:37:50 -0000 1.16 +++ pci/psycho.c 6 Nov 2002 23:20:54 -0000 @@ -630,7 +630,7 @@ * the firmware uses the same model as this driver if it does. * Additionally, set up the bus numbers and ranges. */ - ofw_pci_init(dev, sc->sc_node, &obd); + ofw_pci_init(dev, sc->sc_node, sc->sc_ign, &obd); device_add_child(dev, "pci", device_get_unit(dev)); return (bus_generic_attach(dev)); Index: sparc64/machdep.c =================================================================== RCS file: /space/ncvs/src/sys/sparc64/sparc64/machdep.c,v retrieving revision 1.69 diff -u -r1.69 machdep.c --- sparc64/machdep.c 25 Oct 2002 19:10:58 -0000 1.69 +++ sparc64/machdep.c 6 Nov 2002 23:20:54 -0000 @@ -130,6 +130,8 @@ static struct timecounter tick_tc; +char sparc64_model[128]; + static timecounter_get_t tick_get_timecount; void sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec); @@ -159,6 +161,7 @@ tc_init(&tick_tc); cpu_identify(rdpr(ver), tick_freq, PCPU_GET(cpuid)); + printf("Model: %s\n", sparc64_model); vm_ksubmap_init(&kmi); @@ -348,6 +351,8 @@ OF_getprop(PCPU_GET(node), "clock-frequency", &clock, sizeof(clock)); tick_init(clock); + + OF_getprop(root, "name", sparc64_model, sizeof(sparc64_model) - 1); } void Index: sparc64/ofw_bus.c =================================================================== RCS file: /space/ncvs/src/sys/sparc64/sparc64/ofw_bus.c,v retrieving revision 1.2 diff -u -r1.2 ofw_bus.c --- sparc64/ofw_bus.c 24 Mar 2002 02:11:04 -0000 1.2 +++ sparc64/ofw_bus.c 6 Nov 2002 23:43:00 -0000 @@ -151,15 +151,16 @@ * 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 a match occurs, we should continue to search, using the new interrupt + * specification that was just found; this is currently not performed + * (see below). * 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) +ofw_bus_route_intr(phandle_t node, int intrp, obr_callback_t *cb) { u_int8_t *reg, *intr, *tintr, *imap, *imapmsk; phandle_t parent; @@ -193,8 +194,22 @@ panic("ofw_bus_route_intr: could not get reg property"); imapsz = OF_getprop_alloc(parent, "interrupt-map", 1, (void **)&imap); - if (imapsz == -1) + if (imapsz == -1) { + /* + * Use the callback to allow caller-specific workarounds + * for firmware bugs (missing properties). + */ + if (cb != NULL) { + tisz = cb(parent, intr, isz, reg, regsz, &tintr, + &found); + if (tisz != -1) { + isz = tisz; + free(intr, M_OFWPROP); + intr = tintr; + } + } continue; + } if (OF_getprop(parent, "#address-cells", &addrc, sizeof(addrc)) == -1) addrc = 2;