diff options
-rw-r--r-- | Documentation/admin-guide/kernel-parameters.txt | 2 | ||||
-rw-r--r-- | drivers/iommu/amd_iommu.c | 11 | ||||
-rw-r--r-- | drivers/iommu/intel-iommu.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/amazon/ena/ena_netdev.c | 28 | ||||
-rw-r--r-- | drivers/nvme/host/pci.c | 20 | ||||
-rw-r--r-- | drivers/pci/Kconfig | 12 | ||||
-rw-r--r-- | drivers/pci/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/ats.c | 3 | ||||
-rw-r--r-- | drivers/pci/iov.c | 42 | ||||
-rw-r--r-- | drivers/pci/pci-pf-stub.c | 54 | ||||
-rw-r--r-- | drivers/pci/pci.c | 11 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 20 | ||||
-rw-r--r-- | include/linux/pci.h | 4 | ||||
-rw-r--r-- | include/linux/pci_ids.h | 2 |
14 files changed, 159 insertions, 54 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 11fc28ecdb6d..a19ccac3b4c7 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3147,6 +3147,8 @@ on: Turn realloc on realloc same as realloc=on noari do not use PCIe ARI. + noats [PCIE, Intel-IOMMU, AMD-IOMMU] + do not use PCIe ATS (and IOMMU device IOTLB). pcie_scan_all Scan all possible PCIe devices. Otherwise we only look for one device below a PCIe downstream port. diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 2a99f0f14795..56da1c6121d3 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -355,6 +355,9 @@ static bool pci_iommuv2_capable(struct pci_dev *pdev) }; int i, pos; + if (pci_ats_disabled()) + return false; + for (i = 0; i < 3; ++i) { pos = pci_find_ext_capability(pdev, caps[i]); if (pos == 0) @@ -3524,9 +3527,11 @@ int amd_iommu_device_info(struct pci_dev *pdev, memset(info, 0, sizeof(*info)); - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ATS); - if (pos) - info->flags |= AMD_IOMMU_DEVICE_FLAG_ATS_SUP; + if (!pci_ats_disabled()) { + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ATS); + if (pos) + info->flags |= AMD_IOMMU_DEVICE_FLAG_ATS_SUP; + } pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); if (pos) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 749d8f235346..772b404a6604 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2459,7 +2459,8 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, if (dev && dev_is_pci(dev)) { struct pci_dev *pdev = to_pci_dev(info->dev); - if (ecap_dev_iotlb_support(iommu->ecap) && + if (!pci_ats_disabled() && + ecap_dev_iotlb_support(iommu->ecap) && pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ATS) && dmar_find_matched_atsr_unit(pdev)) info->ats_supported = 1; diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index a822e70c2af3..f2af87d70594 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -3386,32 +3386,6 @@ err_disable_device: } /*****************************************************************************/ -static int ena_sriov_configure(struct pci_dev *dev, int numvfs) -{ - int rc; - - if (numvfs > 0) { - rc = pci_enable_sriov(dev, numvfs); - if (rc != 0) { - dev_err(&dev->dev, - "pci_enable_sriov failed to enable: %d vfs with the error: %d\n", - numvfs, rc); - return rc; - } - - return numvfs; - } - - if (numvfs == 0) { - pci_disable_sriov(dev); - return 0; - } - - return -EINVAL; -} - -/*****************************************************************************/ -/*****************************************************************************/ /* ena_remove - Device Removal Routine * @pdev: PCI device information struct @@ -3526,7 +3500,7 @@ static struct pci_driver ena_pci_driver = { .suspend = ena_suspend, .resume = ena_resume, #endif - .sriov_configure = ena_sriov_configure, + .sriov_configure = pci_sriov_configure_simple, }; static int __init ena_init(void) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index fbc71fac6f1e..284cdd336271 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2598,24 +2598,6 @@ static void nvme_remove(struct pci_dev *pdev) nvme_put_ctrl(&dev->ctrl); } -static int nvme_pci_sriov_configure(struct pci_dev *pdev, int numvfs) -{ - int ret = 0; - - if (numvfs == 0) { - if (pci_vfs_assigned(pdev)) { - dev_warn(&pdev->dev, - "Cannot disable SR-IOV VFs while assigned\n"); - return -EPERM; - } - pci_disable_sriov(pdev); - return 0; - } - - ret = pci_enable_sriov(pdev, numvfs); - return ret ? ret : numvfs; -} - #ifdef CONFIG_PM_SLEEP static int nvme_suspend(struct device *dev) { @@ -2734,7 +2716,7 @@ static struct pci_driver nvme_driver = { .driver = { .pm = &nvme_dev_pm_ops, }, - .sriov_configure = nvme_pci_sriov_configure, + .sriov_configure = pci_sriov_configure_simple, .err_handler = &nvme_err_handler, }; diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 34b56a8f8480..cdef2a2a9bc5 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -71,6 +71,18 @@ config PCI_STUB When in doubt, say N. +config PCI_PF_STUB + tristate "PCI PF Stub driver" + depends on PCI + depends on PCI_IOV + help + Say Y or M here if you want to enable support for devices that + require SR-IOV support, while at the same time the PF itself is + not providing any actual services on the host itself such as + storage or networking. + + When in doubt, say N. + config XEN_PCIDEV_FRONTEND tristate "Xen PCI Frontend" depends on PCI && X86 && XEN diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 952addc7bacf..84c9eef6b1c3 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_PCI_LABEL) += pci-label.o obj-$(CONFIG_X86_INTEL_MID) += pci-mid.o obj-$(CONFIG_PCI_SYSCALL) += syscall.o obj-$(CONFIG_PCI_STUB) += pci-stub.o +obj-$(CONFIG_PCI_PF_STUB) += pci-pf-stub.o obj-$(CONFIG_PCI_ECAM) += ecam.o obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index 89305b569d3d..4923a2a8e14b 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -20,6 +20,9 @@ void pci_ats_init(struct pci_dev *dev) { int pos; + if (pci_ats_disabled()) + return; + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); if (!pos) return; diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 8adf4a64f291..d0d73dbbd5ca 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -469,6 +469,7 @@ found: iov->nres = nres; iov->ctrl = ctrl; iov->total_VFs = total; + iov->driver_max_VFs = total; pci_read_config_word(dev, pos + PCI_SRIOV_VF_DID, &iov->vf_device); iov->pgsz = pgsz; iov->self = dev; @@ -827,9 +828,42 @@ int pci_sriov_get_totalvfs(struct pci_dev *dev) if (!dev->is_physfn) return 0; - if (dev->sriov->driver_max_VFs) - return dev->sriov->driver_max_VFs; - - return dev->sriov->total_VFs; + return dev->sriov->driver_max_VFs; } EXPORT_SYMBOL_GPL(pci_sriov_get_totalvfs); + +/** + * pci_sriov_configure_simple - helper to configure SR-IOV + * @dev: the PCI device + * @nr_virtfn: number of virtual functions to enable, 0 to disable + * + * Enable or disable SR-IOV for devices that don't require any PF setup + * before enabling SR-IOV. Return value is negative on error, or number of + * VFs allocated on success. + */ +int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn) +{ + int rc; + + might_sleep(); + + if (!dev->is_physfn) + return -ENODEV; + + if (pci_vfs_assigned(dev)) { + pci_warn(dev, "Cannot modify SR-IOV while VFs are assigned\n"); + return -EPERM; + } + + if (nr_virtfn == 0) { + sriov_disable(dev); + return 0; + } + + rc = sriov_enable(dev, nr_virtfn); + if (rc < 0) + return rc; + + return nr_virtfn; +} +EXPORT_SYMBOL_GPL(pci_sriov_configure_simple); diff --git a/drivers/pci/pci-pf-stub.c b/drivers/pci/pci-pf-stub.c new file mode 100644 index 000000000000..9795649fc6f9 --- /dev/null +++ b/drivers/pci/pci-pf-stub.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* pci-pf-stub - simple stub driver for PCI SR-IOV PF device + * + * This driver is meant to act as a "whitelist" for devices that provde + * SR-IOV functionality while at the same time not actually needing a + * driver of their own. + */ + +#include <linux/module.h> +#include <linux/pci.h> + +/** + * pci_pf_stub_whitelist - White list of devices to bind pci-pf-stub onto + * + * This table provides the list of IDs this driver is supposed to bind + * onto. You could think of this as a list of "quirked" devices where we + * are adding support for SR-IOV here since there are no other drivers + * that they would be running under. + */ +static const struct pci_device_id pci_pf_stub_whitelist[] = { + { PCI_VDEVICE(AMAZON, 0x0053) }, + /* required last entry */ + { 0 } +}; +MODULE_DEVICE_TABLE(pci, pci_pf_stub_whitelist); + +static int pci_pf_stub_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + pci_info(dev, "claimed by pci-pf-stub\n"); + return 0; +} + +static struct pci_driver pf_stub_driver = { + .name = "pci-pf-stub", + .id_table = pci_pf_stub_whitelist, + .probe = pci_pf_stub_probe, + .sriov_configure = pci_sriov_configure_simple, +}; + +static int __init pci_pf_stub_init(void) +{ + return pci_register_driver(&pf_stub_driver); +} + +static void __exit pci_pf_stub_exit(void) +{ + pci_unregister_driver(&pf_stub_driver); +} + +module_init(pci_pf_stub_init); +module_exit(pci_pf_stub_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1da93e6e8623..b345d20227b8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -112,6 +112,14 @@ unsigned int pcibios_max_latency = 255; /* If set, the PCIe ARI capability will not be used. */ static bool pcie_ari_disabled; +/* If set, the PCIe ATS capability will not be used. */ +static bool pcie_ats_disabled; + +bool pci_ats_disabled(void) +{ + return pcie_ats_disabled; +} + /* Disable bridge_d3 for all PCIe ports */ static bool pci_bridge_d3_disable; /* Force bridge_d3 for all PCIe ports */ @@ -5777,6 +5785,9 @@ static int __init pci_setup(char *str) if (*str && (str = pcibios_setup(str)) && *str) { if (!strcmp(str, "nomsi")) { pci_no_msi(); + } else if (!strncmp(str, "noats", 5)) { + pr_info("PCIe: ATS is disabled\n"); + pcie_ats_disabled = true; } else if (!strcmp(str, "noaer")) { pci_no_aer(); } else if (!strncmp(str, "realloc=", 8)) { diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e7bf44515fd6..341d3a138217 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4230,11 +4230,29 @@ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags) * 0xa290-0xa29f PCI Express Root port #{0-16} * 0xa2e7-0xa2ee PCI Express Root port #{17-24} * + * Mobile chipsets are also affected, 7th & 8th Generation + * Specification update confirms ACS errata 22, status no fix: (7th Generation + * Intel Processor Family I/O for U/Y Platforms and 8th Generation Intel + * Processor Family I/O for U Quad Core Platforms Specification Update, + * August 2017, Revision 002, Document#: 334660-002)[6] + * Device IDs from I/O datasheet: (7th Generation Intel Processor Family I/O + * for U/Y Platforms and 8th Generation Intel ® Processor Family I/O for U + * Quad Core Platforms, Vol 1 of 2, August 2017, Document#: 334658-003)[7] + * + * 0x9d10-0x9d1b PCI Express Root port #{1-12} + * + * The 300 series chipset suffers from the same bug so include those root + * ports here as well. + * + * 0xa32c-0xa343 PCI Express Root port #{0-24} + * * [1] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-2.html * [2] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-1.html * [3] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-spec-update.html * [4] http://www.intel.com/content/www/us/en/chipsets/200-series-chipset-pch-spec-update.html * [5] http://www.intel.com/content/www/us/en/chipsets/200-series-chipset-pch-datasheet-vol-1.html + * [6] https://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-u-y-processor-lines-i-o-spec-update.html + * [7] https://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-u-y-processor-lines-i-o-datasheet-vol-1.html */ static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev) { @@ -4244,6 +4262,8 @@ static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev) switch (dev->device) { case 0xa110 ... 0xa11f: case 0xa167 ... 0xa16a: /* Sunrise Point */ case 0xa290 ... 0xa29f: case 0xa2e7 ... 0xa2ee: /* Union Point */ + case 0x9d10 ... 0x9d1b: /* 7th & 8th Gen Mobile */ + case 0xa32c ... 0xa343: /* 300 series */ return true; } diff --git a/include/linux/pci.h b/include/linux/pci.h index d87556c7af07..fb1a42251d17 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1485,6 +1485,8 @@ static inline void pcie_set_ecrc_checking(struct pci_dev *dev) { } static inline void pcie_ecrc_get_policy(char *str) { } #endif +bool pci_ats_disabled(void); + #ifdef CONFIG_PCI_ATS /* Address Translation Service */ void pci_ats_init(struct pci_dev *dev); @@ -1957,6 +1959,7 @@ int pci_num_vf(struct pci_dev *dev); int pci_vfs_assigned(struct pci_dev *dev); int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs); int pci_sriov_get_totalvfs(struct pci_dev *dev); +int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn); resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno); void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe); @@ -1989,6 +1992,7 @@ static inline int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) { return 0; } static inline int pci_sriov_get_totalvfs(struct pci_dev *dev) { return 0; } +#define pci_sriov_configure_simple NULL static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno) { return 0; } static inline void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe) { } diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 5aace6cca0d7..2609f7e11d06 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2555,6 +2555,8 @@ #define PCI_VENDOR_ID_CIRCUITCO 0x1cc8 #define PCI_SUBSYSTEM_ID_CIRCUITCO_MINNOWBOARD 0x0001 +#define PCI_VENDOR_ID_AMAZON 0x1d0f + #define PCI_VENDOR_ID_TEKRAM 0x1de1 #define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29 |