diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/pci.c | 49 | ||||
-rw-r--r-- | sys/dev/pci/pci_pci.c | 170 | ||||
-rw-r--r-- | sys/dev/pci/pcib_if.m | 19 | ||||
-rw-r--r-- | sys/dev/pci/pcib_private.h | 7 | ||||
-rw-r--r-- | sys/dev/pci/pcib_support.c | 6 | ||||
-rw-r--r-- | sys/dev/pci/pcireg.h | 8 |
6 files changed, 242 insertions, 17 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index ac29705..172ce81 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -354,6 +354,11 @@ SYSCTL_INT(_hw_pci, OID_AUTO, clear_buses, CTLFLAG_RDTUN, &pci_clear_buses, 0, "Ignore firmware-assigned bus numbers."); #endif +static int pci_enable_ari = 1; +TUNABLE_INT("hw.pci.enable_ari", &pci_enable_ari); +SYSCTL_INT(_hw_pci, OID_AUTO, enable_ari, CTLFLAG_RDTUN, &pci_enable_ari, + 0, "Enable support for PCIe Alternative RID Interpretation"); + static int pci_has_quirk(uint32_t devid, int quirk) { @@ -3454,6 +3459,19 @@ pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask) #endif } +static struct pci_devinfo * +pci_identify_function(device_t pcib, device_t dev, int domain, int busno, + int slot, int func, size_t dinfo_size) +{ + struct pci_devinfo *dinfo; + + dinfo = pci_read_device(pcib, domain, busno, slot, func, dinfo_size); + if (dinfo != NULL) + pci_add_child(dev, dinfo); + + return (dinfo); +} + void pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size) { @@ -3463,6 +3481,24 @@ pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size) int maxslots; int s, f, pcifunchigh; uint8_t hdrtype; + int first_func; + + /* + * Try to detect a device at slot 0, function 0. If it exists, try to + * enable ARI. We must enable ARI before detecting the rest of the + * functions on this bus as ARI changes the set of slots and functions + * that are legal on this bus. + */ + dinfo = pci_identify_function(pcib, dev, domain, busno, 0, 0, + dinfo_size); + if (dinfo != NULL && pci_enable_ari) + PCIB_TRY_ENABLE_ARI(pcib, dinfo->cfg.dev); + + /* + * Start looking for new devices on slot 0 at function 1 because we + * just identified the device at slot 0, function 0. + */ + first_func = 1; KASSERT(dinfo_size >= sizeof(struct pci_devinfo), ("dinfo_size too small")); @@ -3475,14 +3511,13 @@ pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size) if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) continue; if (hdrtype & PCIM_MFDEV) - pcifunchigh = PCI_FUNCMAX; - for (f = 0; f <= pcifunchigh; f++) { - dinfo = pci_read_device(pcib, domain, busno, s, f, + pcifunchigh = PCIB_MAXFUNCS(pcib); + for (f = first_func; f <= pcifunchigh; f++) + pci_identify_function(pcib, dev, domain, busno, s, f, dinfo_size); - if (dinfo != NULL) { - pci_add_child(dev, dinfo); - } - } + + /* For slots after slot 0 we need to check for function 0. */ + first_func = 0; } #undef REG } diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c index 2152c23..8b50219 100644 --- a/sys/dev/pci/pci_pci.c +++ b/sys/dev/pci/pci_pci.c @@ -56,6 +56,14 @@ static int pcib_suspend(device_t dev); static int pcib_resume(device_t dev); static int pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate); +static uint16_t pcib_ari_get_rid(device_t pcib, device_t dev); +static uint32_t pcib_read_config(device_t dev, u_int b, u_int s, + u_int f, u_int reg, int width); +static void pcib_write_config(device_t dev, u_int b, u_int s, + u_int f, u_int reg, uint32_t val, int width); +static int pcib_ari_maxslots(device_t dev); +static int pcib_ari_maxfuncs(device_t dev); +static int pcib_try_enable_ari(device_t pcib, device_t dev); static device_method_t pcib_methods[] = { /* Device interface */ @@ -83,7 +91,8 @@ static device_method_t pcib_methods[] = { DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), /* pcib interface */ - DEVMETHOD(pcib_maxslots, pcib_maxslots), + DEVMETHOD(pcib_maxslots, pcib_ari_maxslots), + DEVMETHOD(pcib_maxfuncs, pcib_ari_maxfuncs), DEVMETHOD(pcib_read_config, pcib_read_config), DEVMETHOD(pcib_write_config, pcib_write_config), DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), @@ -93,7 +102,8 @@ static device_method_t pcib_methods[] = { DEVMETHOD(pcib_release_msix, pcib_release_msix), DEVMETHOD(pcib_map_msi, pcib_map_msi), DEVMETHOD(pcib_power_for_sleep, pcib_power_for_sleep), - DEVMETHOD(pcib_get_rid, pcib_get_rid), + DEVMETHOD(pcib_get_rid, pcib_ari_get_rid), + DEVMETHOD(pcib_try_enable_ari, pcib_try_enable_ari), DEVMETHOD_END }; @@ -1803,27 +1813,94 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, #endif /* + * If ARI is enabled on this downstream port, translate the function number + * to the non-ARI slot/function. The downstream port will convert it back in + * hardware. If ARI is not enabled slot and func are not modified. + */ +static __inline void +pcib_xlate_ari(device_t pcib, int bus, int *slot, int *func) +{ + struct pcib_softc *sc; + int ari_func; + + sc = device_get_softc(pcib); + ari_func = *func; + + if (sc->flags & PCIB_ENABLE_ARI) { + KASSERT(*slot == 0, + ("Non-zero slot number with ARI enabled!")); + *slot = PCIE_ARI_SLOT(ari_func); + *func = PCIE_ARI_FUNC(ari_func); + } +} + + +static void +pcib_enable_ari(struct pcib_softc *sc, uint32_t pcie_pos) +{ + uint32_t ctl2; + + ctl2 = pci_read_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, 4); + ctl2 |= PCIEM_CTL2_ARI; + pci_write_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, ctl2, 4); + + sc->flags |= PCIB_ENABLE_ARI; +} + +/* * PCIB interface. */ int pcib_maxslots(device_t dev) { - return(PCI_SLOTMAX); + return (PCI_SLOTMAX); +} + +static int +pcib_ari_maxslots(device_t dev) +{ + struct pcib_softc *sc; + + sc = device_get_softc(dev); + + if (sc->flags & PCIB_ENABLE_ARI) + return (PCIE_ARI_SLOTMAX); + else + return (PCI_SLOTMAX); +} + +static int +pcib_ari_maxfuncs(device_t dev) +{ + struct pcib_softc *sc; + + sc = device_get_softc(dev); + + if (sc->flags & PCIB_ENABLE_ARI) + return (PCIE_ARI_FUNCMAX); + else + return (PCI_FUNCMAX); } /* * Since we are a child of a PCI bus, its parent must support the pcib interface. */ -uint32_t +static uint32_t pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) { - return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width)); + + pcib_xlate_ari(dev, b, &s, &f); + return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, + f, reg, width)); } -void +static void pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width) { - PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width); + + pcib_xlate_ari(dev, b, &s, &f); + PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, + reg, val, width); } /* @@ -1936,3 +2013,82 @@ pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate)); } +static uint16_t +pcib_ari_get_rid(device_t pcib, device_t dev) +{ + struct pcib_softc *sc; + uint8_t bus, slot, func; + + sc = device_get_softc(pcib); + + if (sc->flags & PCIB_ENABLE_ARI) { + bus = pci_get_bus(dev); + func = pci_get_function(dev); + + return (PCI_ARI_RID(bus, func)); + } else { + bus = pci_get_bus(dev); + slot = pci_get_slot(dev); + func = pci_get_function(dev); + + return (PCI_RID(bus, slot, func)); + } +} + +/* + * Check that the downstream port (pcib) and the endpoint device (dev) both + * support ARI. If so, enable it and return 0, otherwise return an error. + */ +static int +pcib_try_enable_ari(device_t pcib, device_t dev) +{ + struct pcib_softc *sc; + int error; + uint32_t cap2; + int ari_cap_off; + uint32_t ari_ver; + uint32_t pcie_pos; + + sc = device_get_softc(pcib); + + /* + * ARI is controlled in a register in the PCIe capability structure. + * If the downstream port does not have the PCIe capability structure + * then it does not support ARI. + */ + error = pci_find_cap(pcib, PCIY_EXPRESS, &pcie_pos); + if (error != 0) + return (ENODEV); + + /* Check that the PCIe port advertises ARI support. */ + cap2 = pci_read_config(pcib, pcie_pos + PCIER_DEVICE_CAP2, 4); + if (!(cap2 & PCIEM_CAP2_ARI)) + return (ENODEV); + + /* + * Check that the endpoint device advertises ARI support via the ARI + * extended capability structure. + */ + error = pci_find_extcap(dev, PCIZ_ARI, &ari_cap_off); + if (error != 0) + return (ENODEV); + + /* + * Finally, check that the endpoint device supports the same version + * of ARI that we do. + */ + ari_ver = pci_read_config(dev, ari_cap_off, 4); + if (PCI_EXTCAP_VER(ari_ver) != PCIB_SUPPORTED_ARI_VER) { + if (bootverbose) + device_printf(pcib, + "Unsupported version of ARI (%d) detected\n", + PCI_EXTCAP_VER(ari_ver)); + + return (ENXIO); + } + + pcib_enable_ari(sc, pcie_pos); + + return (0); +} + diff --git a/sys/dev/pci/pcib_if.m b/sys/dev/pci/pcib_if.m index e8147da..835e2c3 100644 --- a/sys/dev/pci/pcib_if.m +++ b/sys/dev/pci/pcib_if.m @@ -27,7 +27,9 @@ # #include <sys/bus.h> +#include <sys/rman.h> #include <dev/pci/pcivar.h> +#include <dev/pci/pcib_private.h> INTERFACE pcib; @@ -47,6 +49,14 @@ METHOD int maxslots { }; # +# +# Return the number of functions on the attached PCI bus. +# +METHOD int maxfuncs { + device_t dev; +} DEFAULT pcib_maxfuncs; + +# # Read configuration space on the PCI bus. The bus, slot and func # arguments determine the device which is being read and the reg # argument is a byte offset into configuration space for that @@ -161,5 +171,14 @@ METHOD int power_for_sleep { METHOD uint16_t get_rid { device_t pcib; device_t dev; +} DEFAULT pcib_get_rid; + +# +# Enable Alternative RID Interpretation if both the downstream port (pcib) +# and the endpoint device (dev) both support it. +# +METHOD int try_enable_ari { + device_t pcib; + device_t dev; }; diff --git a/sys/dev/pci/pcib_private.h b/sys/dev/pci/pcib_private.h index 6001b2e..cbc2b85 100644 --- a/sys/dev/pci/pcib_private.h +++ b/sys/dev/pci/pcib_private.h @@ -105,6 +105,7 @@ struct pcib_softc #define PCIB_SUBTRACTIVE 0x1 #define PCIB_DISABLE_MSI 0x2 #define PCIB_DISABLE_MSIX 0x4 +#define PCIB_ENABLE_ARI 0x8 uint16_t command; /* command register */ u_int domain; /* domain number */ u_int pribus; /* primary bus number */ @@ -126,6 +127,8 @@ struct pcib_softc uint8_t seclat; /* secondary bus latency timer */ }; +#define PCIB_SUPPORTED_ARI_VER 1 + typedef uint32_t pci_read_config_fn(int b, int s, int f, int reg, int width); int host_pcib_get_busno(pci_read_config_fn read_config, int bus, @@ -159,8 +162,7 @@ int pcib_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r); #endif int pcib_maxslots(device_t dev); -uint32_t pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width); -void pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width); +int pcib_maxfuncs(device_t dev); int pcib_route_interrupt(device_t pcib, device_t dev, int pin); int pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs); int pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs); @@ -169,5 +171,4 @@ int pcib_release_msix(device_t pcib, device_t dev, int irq); int pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data); uint16_t pcib_get_rid(device_t pcib, device_t dev); - #endif diff --git a/sys/dev/pci/pcib_support.c b/sys/dev/pci/pcib_support.c index 48b94c9..6f019fd 100644 --- a/sys/dev/pci/pcib_support.c +++ b/sys/dev/pci/pcib_support.c @@ -48,6 +48,12 @@ __FBSDID("$FreeBSD$"); #include "pcib_if.h" +int +pcib_maxfuncs(device_t dev) +{ + return (PCI_FUNCMAX); +} + uint16_t pcib_get_rid(device_t pcib, device_t dev) { diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index ccd41b5..6e873c8 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -48,6 +48,9 @@ #define PCIE_REGMAX 4095 /* highest supported config register addr. */ #define PCI_MAXHDRTYPE 2 +#define PCIE_ARI_SLOTMAX 0 +#define PCIE_ARI_FUNCMAX 255 + #define PCI_RID_BUS_SHIFT 8 #define PCI_RID_SLOT_SHIFT 3 #define PCI_RID_FUNC_SHIFT 0 @@ -65,6 +68,9 @@ #define PCI_RID2SLOT(rid) (((rid) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX) #define PCI_RID2FUNC(rid) (((rid) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX) +#define PCIE_ARI_SLOT(func) (((func) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX) +#define PCIE_ARI_FUNC(func) (((func) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX) + /* PCI config header registers for all devices */ #define PCIR_DEVVENDOR 0x00 @@ -791,6 +797,7 @@ #define PCIEM_ROOT_STA_PME_STATUS 0x00010000 #define PCIEM_ROOT_STA_PME_PEND 0x00020000 #define PCIER_DEVICE_CAP2 0x24 +#define PCIEM_CAP2_ARI 0x20 #define PCIER_DEVICE_CTL2 0x28 #define PCIEM_CTL2_COMP_TIMEOUT_VAL 0x000f #define PCIEM_CTL2_COMP_TIMEOUT_DIS 0x0010 @@ -911,3 +918,4 @@ /* Serial Number definitions */ #define PCIR_SERIAL_LOW 0x04 #define PCIR_SERIAL_HIGH 0x08 + |