phandle_t ofw_pci_find_node(int bus, int slot, int func) { phandle_t node, bnode; struct ofw_pci_register pcir; /* * Retrieve the bus node from the mapping that was created on * initialization. The bus numbers the firmware uses cannot be trusted, * so they might have needed to be changed and this is necessary. */ if (bus >= pci_bus_map_sz) return (0); bnode = pci_bus_map[bus]; if (bnode == 0) return (0); for (node = OF_child(bnode); node != 0 && node != -1; node = OF_peer(node)) { if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) continue; if (OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi) == slot && OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi) == func) return (node); } return (0); }
static int ofw_pcibus_attach(device_t dev) { device_t pcib; struct ofw_pci_register pcir; struct ofw_pcibus_devinfo *dinfo; phandle_t node, child; uint32_t clock; u_int busno, domain, func, slot; pcib = device_get_parent(dev); domain = pcib_get_domain(dev); busno = pcib_get_bus(dev); if (bootverbose) device_printf(dev, "domain=%d, physical bus=%d\n", domain, busno); node = ofw_bus_get_node(dev); /* * Add the PCI side of the host-PCI bridge itself to the bus. * Note that we exclude the host-PCIe bridges here as these * have no configuration space implemented themselves. */ if (strcmp(device_get_name(device_get_parent(pcib)), "nexus") == 0 && ofw_bus_get_type(pcib) != NULL && strcmp(ofw_bus_get_type(pcib), OFW_TYPE_PCIE) != 0 && (dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib, domain, busno, 0, 0, sizeof(*dinfo))) != NULL) { if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, node) != 0) pci_freecfg((struct pci_devinfo *)dinfo); else pci_add_child(dev, (struct pci_devinfo *)dinfo); } if (OF_getprop(ofw_bus_get_node(pcib), "clock-frequency", &clock, sizeof(clock)) == -1) clock = 33000000; for (child = OF_child(node); child != 0; child = OF_peer(child)) { if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1) continue; slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi); func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi); /* Some OFW device trees contain dupes. */ if (pci_find_dbsf(domain, busno, slot, func) != NULL) continue; ofw_pcibus_setup_device(pcib, clock, busno, slot, func); dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib, domain, busno, slot, func, sizeof(*dinfo)); if (dinfo == NULL) continue; if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) != 0) { pci_freecfg((struct pci_devinfo *)dinfo); continue; } pci_add_child(dev, (struct pci_devinfo *)dinfo); } return (bus_generic_attach(dev)); }
void genppc_pci_ofmethod_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp) { if (bp != NULL) *bp = OFW_PCI_PHYS_HI_BUS(tag); if (dp != NULL) *dp = OFW_PCI_PHYS_HI_DEVICE(tag); if (fp != NULL) *fp = OFW_PCI_PHYS_HI_FUNCTION(tag); return; }
static void ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno) { device_t pcib; struct ofw_pci_register pcir; struct ofw_pcibus_devinfo *dinfo; phandle_t node, child; u_int func, slot; int intline; pcib = device_get_parent(dev); node = ofw_bus_get_node(dev); for (child = OF_child(node); child != 0; child = OF_peer(child)) { if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1) continue; slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi); func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi); /* Some OFW device trees contain dupes. */ if (pci_find_dbsf(domain, busno, slot, func) != NULL) continue; /* * The preset in the intline register is usually bogus. Reset * it such that the PCI code will reroute the interrupt if * needed. */ intline = PCI_INVALID_IRQ; if (OF_getproplen(child, "interrupts") > 0) intline = 0; PCIB_WRITE_CONFIG(pcib, busno, slot, func, PCIR_INTLINE, intline, 1); /* * Now set up the PCI and OFW bus layer devinfo and add it * to the PCI bus. */ dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib, domain, busno, slot, func, sizeof(*dinfo)); if (dinfo == NULL) continue; if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) != 0) { pci_freecfg((struct pci_devinfo *)dinfo); continue; } dinfo->opd_dma_tag = NULL; pci_add_child(dev, (struct pci_devinfo *)dinfo); /* * Some devices don't have an intpin set, but do have * interrupts. These are fully specified, and set in the * interrupts property, so add that value to the device's * resource list. */ if (dinfo->opd_dinfo.cfg.intpin == 0) ofw_bus_intr_to_rl(dev, child, &dinfo->opd_dinfo.resources, NULL); } }
/* * Walk the PCI bus hierarchy, starting with the root PCI bus and descending * through bridges, and initialize the interrupt line and latency timer * configuration registers of attached devices using firmware information, * as well as the the bus numbers and ranges of the bridges. */ void 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 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; busno = obd->obd_secbus; do { if (node == -1) panic("ofw_pci_init_intr: OF_child failed"); if (OF_getprop(node, "device_type", type, sizeof(type)) == -1) type[0] = '\0'; else type[sizeof(type) - 1] = '\0'; if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) 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) { /* * This is a pci-pci bridge, initalize the bus number and * recurse to initialize the child bus. The hierarchy is * usually at most 2 levels deep, so recursion is * feasible. */ subobd.obd_bus = busno; subobd.obd_slot = slot; subobd.obd_func = func; sub = ofw_pci_alloc_busno(node); subobd.obd_secbus = subobd.obd_subbus = sub; /* Assume this bridge is mostly standard conforming. */ subobd.obd_init = ofw_pci_binit; subobd.obd_super = obd; /* * Need to change all subordinate bus registers of the * bridges above this one now so that configuration * transactions will get through. */ for (tobd = obd; tobd != NULL; tobd = tobd->obd_super) { tobd->obd_subbus = sub; tobd->obd_init(dev, tobd); } subobd.obd_init(dev, &subobd); #ifdef OFW_PCI_DEBUG device_printf(dev, "%s: descending to " "subordinate PCI bus\n", __func__); #endif /* OFW_PCI_DEBUG */ ofw_pci_init(dev, node, ign, &subobd); } else { /* * Initialize the latency timer register for * busmaster devices to work properly. This is another * task which the firmware does not always perform. * The Min_Gnt register can be used to compute it's * recommended value: it contains the desired latency * in units of 1/4 us. To calculate the correct latency * timer value, a bus clock of 33 and no wait states * should be assumed. */ lat = PCIB_READ_CONFIG(dev, busno, slot, func, PCIR_MINGNT, 1) * 33 / 4; if (lat != 0) { #ifdef OFW_PCI_DEBUG printf("device %d/%d/%d: latency timer %d -> " "%d\n", busno, slot, func, PCIB_READ_CONFIG(dev, busno, slot, func, PCIR_LATTIMER, 1), lat); #endif /* OFW_PCI_DEBUG */ PCIB_WRITE_CONFIG(dev, busno, slot, func, PCIR_LATTIMER, imin(lat, 255), 1); } /* Initialize the intline registers. */ 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", __func__, busno, slot, func, intr, (int)PCIB_READ_CONFIG(dev, busno, slot, func, PCIR_INTLINE, 1)); #endif /* OFW_PCI_DEBUG */ PCIB_WRITE_CONFIG(dev, busno, slot, func, PCIR_INTLINE, intr, 1); } else { #ifdef OFW_PCI_DEBUG device_printf(dev, "%s: no interrupt " "mapping found for %d/%d/%d (preset %d)\n", __func__, busno, slot, func, (int)PCIB_READ_CONFIG(dev, busno, slot, func, PCIR_INTLINE, 1)); #endif /* OFW_PCI_DEBUG */ /* * The firmware initializes to 0 instead of * 255. */ PCIB_WRITE_CONFIG(dev, busno, slot, func, PCIR_INTLINE, 255, 1); } } } while ((node = OF_peer(node)) != 0); }