From cef74409ea79b0a37af6889e7abf7a2a9c47979b Mon Sep 17 00:00:00 2001 From: Gil Kupfer Date: Thu, 10 May 2018 17:56:02 -0500 Subject: PCI: Add "pci=noats" boot parameter Adds a "pci=noats" boot parameter. When supplied, all ATS related functions fail immediately and the IOMMU is configured to not use device-IOTLB. Any function that checks for ATS capabilities directly against the devices should also check this flag. Currently, such functions exist only in IOMMU drivers, and they are covered by this patch. The motivation behind this patch is the existence of malicious devices. Lots of research has been done about how to use the IOMMU as protection from such devices. When ATS is supported, any I/O device can access any physical address by faking device-IOTLB entries. Adding the ability to ignore these entries lets sysadmins enhance system security. Signed-off-by: Gil Kupfer Signed-off-by: Bjorn Helgaas Acked-by: Joerg Roedel --- drivers/pci/pci.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e597655a5643..789ce36be341 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 */ @@ -5793,6 +5801,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)) { -- cgit v1.2.3 From ae07b786888f1872ac2b63d74a17e206d441ec9f Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 15 May 2018 11:07:00 +0200 Subject: PCI: Make pci_get_new_domain_nr() static The only user of pci_get_new_domain_nr() is of_pci_bus_find_domain_nr(). Since they are defined in the same file, pci_get_new_domain_nr() can be made static, which also simplifies preprocessor conditionals. No functional change intended. Signed-off-by: Jan Kiszka Signed-off-by: Bjorn Helgaas Acked-by: Lorenzo Pieralisi --- drivers/pci/pci.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e597655a5643..695c2bb4e853 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5702,15 +5702,14 @@ static void pci_no_domains(void) #endif } -#ifdef CONFIG_PCI_DOMAINS +#ifdef CONFIG_PCI_DOMAINS_GENERIC static atomic_t __domain_nr = ATOMIC_INIT(-1); -int pci_get_new_domain_nr(void) +static int pci_get_new_domain_nr(void) { return atomic_inc_return(&__domain_nr); } -#ifdef CONFIG_PCI_DOMAINS_GENERIC static int of_pci_bus_find_domain_nr(struct device *parent) { static int use_dt_domains = -1; @@ -5765,7 +5764,6 @@ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent) acpi_pci_bus_find_domain_nr(bus); } #endif -#endif /** * pci_ext_cfg_avail - can we access extended PCI config space? -- cgit v1.2.3 From 9f5a70f18c5893a30d6c339adc48de43c57dd7e2 Mon Sep 17 00:00:00 2001 From: Oza Pawandeep Date: Thu, 17 May 2018 16:44:11 -0500 Subject: PCI: Add generic pcie_wait_for_link() interface Clients such as hotplug and Downstream Port Containment (DPC) both need to wait until a link becomes active or inactive. Add a generic pcie_wait_link_active() interface and use it instead of duplicating the code. Signed-off-by: Oza Pawandeep Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch --- drivers/pci/pci.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e597655a5643..764bf64a097d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4138,6 +4138,35 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS); } +/** + * pcie_wait_for_link - Wait until link is active or inactive + * @pdev: Bridge device + * @active: waiting for active or inactive? + * + * Use this to wait till link becomes active or inactive. + */ +bool pcie_wait_for_link(struct pci_dev *pdev, bool active) +{ + int timeout = 1000; + bool ret; + u16 lnk_status; + + for (;;) { + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); + ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); + if (ret == active) + return true; + if (timeout <= 0) + break; + msleep(10); + timeout -= 10; + } + + pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n", + active ? "set" : "cleared"); + + return false; +} void pci_reset_secondary_bus(struct pci_dev *dev) { -- cgit v1.2.3 From e5b1db0186bfb3bede41e412b27c9bcf2b336622 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 30 Mar 2018 14:41:49 -0500 Subject: PCI: Remove unused pcie_get_minimum_link() In some cases pcie_get_minimum_link() returned misleading information because it found the slowest link and the narrowest link without considering the total bandwidth of the link. For example, consider a path with these two links: - 16.0 GT/s x1 link (16.0 * 10^9 * 128 / 130) * 1 / 8 = 1969 MB/s - 2.5 GT/s x16 link ( 2.5 * 10^9 * 8 / 10) * 16 / 8 = 4000 MB/s The available bandwidth of the path is limited by the 16 GT/s link to about 1969 MB/s, but pcie_get_minimum_link() returned 2.5 GT/s x1, which corresponds to only 250 MB/s. Callers should use pcie_print_link_status() instead, or pcie_bandwidth_available() if they need more detailed information. Remove pcie_get_minimum_link() since there are no callers left. Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 43 ------------------------------------------- 1 file changed, 43 deletions(-) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e597655a5643..4bafa817c40a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5069,49 +5069,6 @@ int pcie_set_mps(struct pci_dev *dev, int mps) } EXPORT_SYMBOL(pcie_set_mps); -/** - * pcie_get_minimum_link - determine minimum link settings of a PCI device - * @dev: PCI device to query - * @speed: storage for minimum speed - * @width: storage for minimum width - * - * This function will walk up the PCI device chain and determine the minimum - * link width and speed of the device. - */ -int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed, - enum pcie_link_width *width) -{ - int ret; - - *speed = PCI_SPEED_UNKNOWN; - *width = PCIE_LNK_WIDTH_UNKNOWN; - - while (dev) { - u16 lnksta; - enum pci_bus_speed next_speed; - enum pcie_link_width next_width; - - ret = pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); - if (ret) - return ret; - - next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS]; - next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >> - PCI_EXP_LNKSTA_NLW_SHIFT; - - if (next_speed < *speed) - *speed = next_speed; - - if (next_width < *width) - *width = next_width; - - dev = dev->bus->self; - } - - return 0; -} -EXPORT_SYMBOL(pcie_get_minimum_link); - /** * pcie_bandwidth_available - determine minimum link settings of a PCIe * device and its bandwidth limitation -- cgit v1.2.3