static int ofw_pcibus_assign_interrupt(device_t dev, device_t child) { ofw_pci_intr_t intr; phandle_t node; int isz; node = ofw_bus_get_node(child); if (node == -1) { /* Non-firmware enumerated child, use standard routing */ /* * XXX: Right now we don't have anything sensible to do here, * since the ofw_imap stuff relies on nodes have a reg * property. There exists ways around this, so the ePAPR * spec will need to be studied. */ return (0); #ifdef NOTYET intr = pci_get_intpin(child); return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr)); #endif } /* * Any AAPL,interrupts property gets priority and is * fully specified (i.e. does not need routing) */ isz = OF_getprop(node, "AAPL,interrupts", &intr, sizeof(intr)); if (isz == sizeof(intr)) { return (intr); } isz = OF_getprop(node, "interrupts", &intr, sizeof(intr)); if (isz != sizeof(intr)) { /* No property; our best guess is the intpin. */ intr = pci_get_intpin(child); } /* * If we got intr from a property, it may or may not be an intpin. * For on-board devices, it frequently is not, and is completely out * of the valid intpin range. For PCI slots, it hopefully is, * otherwise we will have trouble interfacing with non-OFW buses * such as cardbus. * Since we cannot tell which it is without violating layering, we * will always use the route_interrupt method, and treat exceptions * on the level they become apparent. */ return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr)); }
int ofw_pcib_gen_route_interrupt(device_t bridge, device_t dev, int intpin) { struct ofw_pcib_gen_softc *sc; struct ofw_bus_iinfo *ii; struct ofw_pci_register reg; ofw_pci_intr_t pintr, mintr; uint8_t maskbuf[sizeof(reg) + sizeof(pintr)]; sc = device_get_softc(bridge); ii = &sc->ops_iinfo; if (ii->opi_imapsz > 0) { pintr = intpin; if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), NULL, maskbuf)) { /* * If we've found a mapping, return it and don't map * it again on higher levels - that causes problems * in some cases, and never seems to be required. */ return (mintr); } } else if (intpin >= 1 && intpin <= 4) { /* * When an interrupt map is missing, we need to do the * standard PCI swizzle and continue mapping at the parent. */ return (pcib_route_interrupt(bridge, dev, intpin)); } /* Try at the parent. */ return (PCIB_ROUTE_INTERRUPT(device_get_parent(device_get_parent( bridge)), bridge, intpin)); }
static int ofw_pcibus_assign_interrupt(device_t dev, device_t child) { ofw_pci_intr_t intr; int isz; isz = OF_getprop(ofw_bus_get_node(child), "interrupts", &intr, sizeof(intr)); if (isz != sizeof(intr)) { /* No property; our best guess is the intpin. */ intr = pci_get_intpin(child); #ifndef SUN4V } else if (intr >= 255) { /* * A fully specified interrupt (including IGN), as present on * SPARCengine Ultra AX and E450. Extract the INO and return * it. */ return (INTINO(intr)); #endif } /* * If we got intr from a property, it may or may not be an intpin. * For on-board devices, it frequently is not, and is completely out * of the valid intpin range. For PCI slots, it hopefully is, * otherwise we will have trouble interfacing with non-OFW buses * such as cardbus. * Since we cannot tell which it is without violating layering, we * will always use the route_interrupt method, and treat exceptions * on the level they become apparent. */ return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr)); }
/* * Route an interrupt across a PCI bridge. */ static int pcib_route_interrupt(device_t pcib, device_t dev, int pin) { device_t bus; int parent_intpin; int intnum; /* * * The PCI standard defines a swizzle of the child-side device/intpin to * the parent-side intpin as follows. * * device = device on child bus * child_intpin = intpin on child bus slot (0-3) * parent_intpin = intpin on parent bus slot (0-3) * * parent_intpin = (device + child_intpin) % 4 */ parent_intpin = (pci_get_slot(pcib) + (pin - 1)) % 4; /* * Our parent is a PCI bus. Its parent must export the pcib interface * which includes the ability to route interrupts. */ bus = device_get_parent(pcib); intnum = PCIB_ROUTE_INTERRUPT(device_get_parent(bus), pcib, parent_intpin + 1); if (PCI_INTERRUPT_VALID(intnum)) { device_printf(pcib, "slot %d INT%c is routed to irq %d\n", pci_get_slot(dev), 'A' + pin - 1, intnum); } return(intnum); }
ofw_pci_intr_t ofw_isa_route_intr(device_t bridge, phandle_t node, struct ofw_bus_iinfo *ii, ofw_isa_intr_t intr) { struct isa_regs reg; device_t pbridge; ofw_isa_intr_t mintr; pbridge = device_get_parent(device_get_parent(bridge)); /* * If we get a match from using the map, the resulting INO is * fully specified, so we may not continue to map. */ if (!ofw_bus_lookup_imap(node, ii, ®, sizeof(reg), &intr, sizeof(intr), &mintr, sizeof(mintr), NULL)) { /* Try routing at the parent bridge. */ mintr = PCIB_ROUTE_INTERRUPT(pbridge, bridge, intr); } return (mintr); }
static int ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, int intpin) { struct ofw_pcib_softc *sc; struct ofw_bus_iinfo *ii; struct ofw_pci_register reg; cell_t pintr, mintr; phandle_t iparent; uint8_t maskbuf[sizeof(reg) + sizeof(pintr)]; sc = device_get_softc(bridge); ii = &sc->ops_iinfo; if (ii->opi_imapsz > 0) { pintr = intpin; /* Fabricate imap information if this isn't an OFW device */ bzero(®, sizeof(reg)); reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) | (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) | (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT); if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), &iparent, maskbuf)) { /* * If we've found a mapping, return it and don't map * it again on higher levels - that causes problems * in some cases, and never seems to be required. */ return (ofw_bus_map_intr(dev, iparent, mintr)); } } else if (intpin >= 1 && intpin <= 4) { /* * When an interrupt map is missing, we need to do the * standard PCI swizzle and continue mapping at the parent. */ return (pcib_route_interrupt(bridge, dev, intpin)); } return (PCIB_ROUTE_INTERRUPT(device_get_parent(device_get_parent( bridge)), bridge, intpin)); }
static int ofw_pcibus_assign_interrupt(device_t dev, device_t child) { ofw_pci_intr_t intr[2]; phandle_t node, iparent; int isz, icells; node = ofw_bus_get_node(child); if (node == -1) { /* Non-firmware enumerated child, use standard routing */ intr[0] = pci_get_intpin(child); return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr[0])); } /* * Try to determine the node's interrupt parent so we know which * PIC to use. */ iparent = -1; if (OF_getprop(node, "interrupt-parent", &iparent, sizeof(iparent)) < 0) iparent = -1; icells = 1; if (iparent != -1) OF_getprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells, sizeof(icells)); /* * Any AAPL,interrupts property gets priority and is * fully specified (i.e. does not need routing) */ isz = OF_getprop(node, "AAPL,interrupts", intr, sizeof(intr)); if (isz == sizeof(intr[0])*icells) return ((iparent == -1) ? intr[0] : ofw_bus_map_intr(dev, iparent, icells, intr)); isz = OF_getprop(node, "interrupts", intr, sizeof(intr)); if (isz == sizeof(intr[0])*icells) { if (iparent != -1) intr[0] = ofw_bus_map_intr(dev, iparent, icells, intr); } else { /* No property: our best guess is the intpin. */ intr[0] = pci_get_intpin(child); } /* * If we got intr from a property, it may or may not be an intpin. * For on-board devices, it frequently is not, and is completely out * of the valid intpin range. For PCI slots, it hopefully is, * otherwise we will have trouble interfacing with non-OFW buses * such as cardbus. * Since we cannot tell which it is without violating layering, we * will always use the route_interrupt method, and treat exceptions * on the level they become apparent. */ return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr[0])); }