summaryrefslogtreecommitdiffstats
path: root/sys/dev/pci/pci_pci.c
diff options
context:
space:
mode:
authorrstone <rstone@FreeBSD.org>2015-03-01 04:22:06 +0000
committerrstone <rstone@FreeBSD.org>2015-03-01 04:22:06 +0000
commit0b55a8c80a8931d02374a071f01ad9db0ef81d38 (patch)
tree446f913517294e1706cb75904e32f64162cd9d7d /sys/dev/pci/pci_pci.c
parent058f9df18735c3a34032de747c66a1b31569903d (diff)
downloadFreeBSD-src-0b55a8c80a8931d02374a071f01ad9db0ef81d38.zip
FreeBSD-src-0b55a8c80a8931d02374a071f01ad9db0ef81d38.tar.gz
MFC r264007,r264008,r264009,r264011,r264012,r264013
MFC support for PCI Alternate RID Interpretation. ARI is an optional PCIe feature that allows PCI devices to present up to 256 functions on a bus. This is effectively a prerequisite for PCI SR-IOV support. r264007: Add a method to get the PCI RID for a device. Reviewed by: kib MFC after: 2 months Sponsored by: Sandvine Inc. r264008: Re-implement the DMAR I/O MMU code in terms of PCI RIDs Under the hood the VT-d spec is really implemented in terms of PCI RIDs instead of bus/slot/function, even though the spec makes pains to convert back to bus/slot/function in examples. However working with bus/slot/function is not correct when PCI ARI is in use, so convert to using RIDs in most cases. bus/slot/function will only be used when reporting errors to a user. Reviewed by: kib MFC after: 2 months Sponsored by: Sandvine Inc. r264009: Re-write bhyve's I/O MMU handling in terms of PCI RID. Reviewed by: neel MFC after: 2 months Sponsored by: Sandvine Inc. r264011: Add support for PCIe ARI PCIe Alternate RID Interpretation (ARI) is an optional feature that allows devices to have up to 256 different functions. It is implemented by always setting the PCI slot number to 0 and re-purposing the 5 bits used to encode the slot number to instead contain the function number. Combined with the original 3 bits allocated for the function number, this allows for 256 functions. This is enabled by default, but it's expected to be a no-op on currently supported hardware. It's a prerequisite for supporting PCI SR-IOV, and I want the ARI support to go in early to help shake out any bugs in it. ARI can be disabled by setting the tunable hw.pci.enable_ari=0. Reviewed by: kib MFC after: 2 months Sponsored by: Sandvine Inc. r264012: Print status of ARI capability in pciconf -c Teach pciconf how to print out the status (enabled/disabled) of the ARI capability on PCI Root Complexes and Downstream Ports. MFC after: 2 months Sponsored by: Sandvine Inc. r264013: Add missing copyright date. MFC after: 2 months
Diffstat (limited to 'sys/dev/pci/pci_pci.c')
-rw-r--r--sys/dev/pci/pci_pci.c170
1 files changed, 164 insertions, 6 deletions
diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c
index 6457e81..451f660 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,6 +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_ari_get_rid),
+ DEVMETHOD(pcib_try_enable_ari, pcib_try_enable_ari),
DEVMETHOD_END
};
@@ -1630,27 +1641,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);
}
/*
@@ -1762,3 +1840,83 @@ pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate)
bus = device_get_parent(pcib);
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);
+}
+
OpenPOWER on IntegriCloud