From edd33ddaa93e181a8c159d402224dbd528e62b42 Mon Sep 17 00:00:00 2001 From: marius Date: Fri, 30 Nov 2007 23:02:42 +0000 Subject: - Add the PCI side of the HOST-PCI bridge itself to the bus. This is required by the X.Org PCI domains code and additionally needs a workaround for Hummingbird and Sabre bridges as these don't allow their config headers to be read at any width, which is an unusual behavior. - In psycho(4) take advantage of DEFINE_CLASS_0 and use more appropriate types for some softc members. MFC after: 3 days --- sys/sparc64/pci/ofw_pcibus.c | 13 +++++++++ sys/sparc64/pci/psycho.c | 69 +++++++++++++++++++++++++++++++++++++------- sys/sparc64/pci/psychovar.h | 8 +++-- 3 files changed, 76 insertions(+), 14 deletions(-) diff --git a/sys/sparc64/pci/ofw_pcibus.c b/sys/sparc64/pci/ofw_pcibus.c index 0a03696..f771389 100644 --- a/sys/sparc64/pci/ofw_pcibus.c +++ b/sys/sparc64/pci/ofw_pcibus.c @@ -189,6 +189,19 @@ ofw_pcibus_attach(device_t dev) domain, busno); node = ofw_bus_get_node(dev); + +#ifndef SUN4V + /* Add the PCI side of the HOST-PCI bridge itself to the bus. */ + if (strcmp(device_get_name(device_get_parent(pcib)), "nexus") == 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); + } +#endif + for (child = OF_child(node); child != 0; child = OF_peer(child)) { if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1) continue; diff --git a/sys/sparc64/pci/psycho.c b/sys/sparc64/pci/psycho.c index 0c2c92d..6f38700 100644 --- a/sys/sparc64/pci/psycho.c +++ b/sys/sparc64/pci/psycho.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -160,14 +161,10 @@ static device_method_t psycho_methods[] = { { 0, 0 } }; -static driver_t psycho_driver = { - "pcib", - psycho_methods, - sizeof(struct psycho_softc), -}; - static devclass_t psycho_devclass; +DEFINE_CLASS_0(pcib, psycho_driver, psycho_methods, + sizeof(struct psycho_softc)); DRIVER_MODULE(psycho, nexus, psycho_driver, psycho_devclass, 0, 0); static SLIST_HEAD(, psycho_softc) psycho_softcs = @@ -304,9 +301,9 @@ psycho_attach(device_t dev) struct psycho_softc *asc, *sc, *osc; struct ofw_pci_ranges *range; const struct psycho_desc *desc; - phandle_t child, node; bus_addr_t intrclr, intrmap; uint64_t csr, dr; + phandle_t child, node; uint32_t dvmabase, psycho_br[2]; int32_t rev; u_int ver; @@ -676,6 +673,16 @@ psycho_attach(device_t dev) PCIB_WRITE_CONFIG(dev, psycho_br[0], PCS_DEVICE, PCS_FUNC, PCSR_SECBUS, sc->sc_pci_secbus, 1); + for (n = PCIR_VENDOR; n < PCIR_STATUS; n += sizeof(uint16_t)) + le16enc(&sc->sc_pci_hpbcfg[n], bus_space_read_2( + sc->sc_pci_cfgt, sc->sc_pci_bh[OFW_PCI_CS_CONFIG], + PSYCHO_CONF_OFF(sc->sc_pci_secbus, PCS_DEVICE, + PCS_FUNC, n))); + for (n = PCIR_REVID; n <= PCIR_BIST; n += sizeof(uint8_t)) + sc->sc_pci_hpbcfg[n] = bus_space_read_1(sc->sc_pci_cfgt, + sc->sc_pci_bh[OFW_PCI_CS_CONFIG], PSYCHO_CONF_OFF( + sc->sc_pci_secbus, PCS_DEVICE, PCS_FUNC, n)); + ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); /* * On E250 the interrupt map entry for the EBus bridge is wrong, @@ -924,13 +931,53 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, u_long offset = 0; uint8_t byte; uint16_t shrt; - uint32_t wrd; - uint32_t r; + uint32_t r, wrd; int i; sc = device_get_softc(dev); - offset = PSYCHO_CONF_OFF(bus, slot, func, reg); bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; + + /* + * The Hummingbird and Sabre bridges are picky in that they + * only allow their config space to be accessed using the + * "native" width of the respective register being accessed + * and return semi-random other content of their config space + * otherwise. Given that the PCI specs don't say anything + * about such a (unusual) limitation and lots of stuff expects + * to be able to access the contents of the config space at + * any width we allow just that. We do this by using a copy + * of the header of the bridge (the rest is all zero anyway) + * read during attach (expect for PCIR_STATUS) in order to + * simplify things. + * The Psycho bridges contain a dupe of their header at 0x80 + * which we nullify that way also. + */ + if (bus == sc->sc_pci_secbus && slot == PCS_DEVICE && + func == PCS_FUNC) { + if (offset % width != 0) + return (-1); + + if (reg > sizeof(sc->sc_pci_hpbcfg)) + return (0); + + if ((reg < PCIR_STATUS && reg + width > PCIR_STATUS) || + reg == PCIR_STATUS || reg == PCIR_STATUS + 1) + le16enc(&sc->sc_pci_hpbcfg[PCIR_STATUS], + bus_space_read_2(sc->sc_pci_cfgt, bh, + PSYCHO_CONF_OFF(sc->sc_pci_secbus, + PCS_DEVICE, PCS_FUNC, PCIR_STATUS))); + + switch (width) { + case 1: + return (sc->sc_pci_hpbcfg[reg]); + case 2: + return (le16dec(&sc->sc_pci_hpbcfg[reg])); + case 4: + return (le32dec(&sc->sc_pci_hpbcfg[reg])); + } + } + + offset = PSYCHO_CONF_OFF(bus, slot, func, reg); switch (width) { case 1: i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); @@ -1001,7 +1048,7 @@ psycho_route_interrupt(device_t bridge, device_t dev, int pin) /* * If this is outside of the range for an intpin, it's likely a full * INO, and no mapping is required at all; this happens on the U30, - * where there's no interrupt map at the Psycho node. Fortunately, + * where there's no interrupt map at the Psycho node. Fortunately, * there seem to be no INOs in the intpin range on this boxen, so * this easy heuristics will do. */ diff --git a/sys/sparc64/pci/psychovar.h b/sys/sparc64/pci/psychovar.h index ddb4661..b99181d 100644 --- a/sys/sparc64/pci/psychovar.h +++ b/sys/sparc64/pci/psychovar.h @@ -43,17 +43,17 @@ struct psycho_softc { struct mtx *sc_mtx; /* Interrupt Group Number for this device */ - int sc_ign; + uint32_t sc_ign; bus_addr_t sc_pcictl; phandle_t sc_node; /* Firmware node */ - int sc_mode; + u_int sc_mode; #define PSYCHO_MODE_SABRE 1 #define PSYCHO_MODE_PSYCHO 2 /* Bus A or B of a psycho pair? */ - int sc_half; + u_int sc_half; struct iommu_state *sc_is; @@ -77,6 +77,8 @@ struct psycho_softc { struct rman sc_pci_mem_rman; struct rman sc_pci_io_rman; + uint8_t sc_pci_hpbcfg[16]; + SLIST_ENTRY(psycho_softc) sc_link; }; -- cgit v1.1