From 977509f7c5c6fb992ffcdf4291051af343b91645 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 2 Jan 2017 14:04:24 -0600 Subject: PCI: Apply _HPX settings only to relevant devices Previously we didn't check the type of device before trying to apply Type 1 (PCI-X) or Type 2 (PCIe) Setting Records from _HPX. We don't support PCI-X Setting Records, so this was harmless, but the warning was useless. We do support PCIe Setting Records, and we didn't check whether a device was PCIe before applying settings. I don't think anything bad happened on non-PCIe devices because pcie_capability_clear_and_set_word(), pcie_cap_has_lnkctl(), etc., would fail before doing any harm. But it's ugly to depend on those internals. Check the device type before attempting to apply Type 1 and Type 2 Setting Records (Type 0 records are applicable to PCI, PCI-X, and PCIe devices). A side benefit is that this prevents useless "not supported" warnings when a BIOS supplies a Type 1 (PCI-X) Setting Record and we try to apply it to every single device: pci 0000:00:00.0: PCI-X settings not supported After this patch, we'll get the warning only when a BIOS supplies a Type 1 record and we have a PCI-X device to which it should be applied. Link: https://bugzilla.kernel.org/show_bug.cgi?id=187731 Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index e164b5c9f0f0..aca5b2466adb 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1554,8 +1554,16 @@ static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp) static void program_hpp_type1(struct pci_dev *dev, struct hpp_type1 *hpp) { - if (hpp) - dev_warn(&dev->dev, "PCI-X settings not supported\n"); + int pos; + + if (!hpp) + return; + + pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); + if (!pos) + return; + + dev_warn(&dev->dev, "PCI-X settings not supported\n"); } static bool pcie_root_rcb_set(struct pci_dev *dev) @@ -1581,6 +1589,9 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) if (!hpp) return; + if (!pci_is_pcie(dev)) + return; + if (hpp->revision > 1) { dev_warn(&dev->dev, "PCIe settings rev %d not supported\n", hpp->revision); -- cgit v1.2.3 From 53762ba810398c11efaf65f9a45d992125e86dcf Mon Sep 17 00:00:00 2001 From: Zhou Wang Date: Wed, 4 Jan 2017 15:00:06 +0800 Subject: PCI/ACPI: Fix bus range comparison in pci_mcfg_lookup() The configuration data provided by an MCFG entry, i.e., PCI segment and bus range, may span multiple host bridges. pci_mcfg_lookup() previously required an exact match of the host bridge starting bus and the MCFG starting bus, which made the following configuration fail: MCFG region: segment: 0 bus range: 0x00-0xff host bridge segment: 0 bus range: 0x20-0x4f Relax the bus range check in pci_mcfg_lookup() so we can use any MCFG entry that contains the required bus range, as we do in pci_mmconfig_lookup(). [bhelgaas: changelog] Signed-off-by: Zhou Wang Signed-off-by: Bjorn Helgaas Reviewed-by: Tomasz Nowicki Acked-by: Lorenzo Pieralisi --- drivers/acpi/pci_mcfg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index a6a4ceaa6cc3..2944353253ed 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -195,11 +195,10 @@ int pci_mcfg_lookup(struct acpi_pci_root *root, struct resource *cfgres, goto skip_lookup; /* - * We expect exact match, unless MCFG entry end bus covers more than - * specified by caller. + * We expect the range in bus_res in the coverage of MCFG bus range. */ list_for_each_entry(e, &pci_mcfg_list, list) { - if (e->segment == seg && e->bus_start == bus_res->start && + if (e->segment == seg && e->bus_start <= bus_res->start && e->bus_end >= bus_res->end) { root->mcfg_addr = e->addr; } -- cgit v1.2.3 From cdcb33f9824429a926b971bf041a6cec238f91ff Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 13 Jan 2017 18:05:12 -0600 Subject: PCI: Avoid possible deadlock on pci_lock and p->pi_lock pci_lock is an IRQ-safe spinlock that protects all accesses to PCI configuration space (see PCI_OP_READ() and PCI_OP_WRITE() in pci/access.c). The pci_cfg_access_unlock() path acquires pci_lock, then p->pi_lock (inside wake_up_all()). According to lockdep, there is a possible path involving snbep_uncore_pci_read_counter() that could acquire them in the reverse order: acquiring p->pi_lock, then pci_lock, which could result in a deadlock. Lockdep details are in the bugzilla below. Avoid the possible deadlock by dropping pci_lock before waking up any config access waiters. Link: https://bugzilla.kernel.org/show_bug.cgi?id=192901 Signed-off-by: Bjorn Helgaas --- drivers/pci/access.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/access.c b/drivers/pci/access.c index db239547fefd..68bd7201d8bc 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -684,8 +684,9 @@ void pci_cfg_access_unlock(struct pci_dev *dev) WARN_ON(!dev->block_cfg_access); dev->block_cfg_access = 0; - wake_up_all(&pci_cfg_wait); raw_spin_unlock_irqrestore(&pci_lock, flags); + + wake_up_all(&pci_cfg_wait); } EXPORT_SYMBOL_GPL(pci_cfg_access_unlock); -- cgit v1.2.3 From 60db3a4d8cc9073cf56264785197ba75ee1caca4 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 20 Jan 2017 09:16:51 -0500 Subject: PCI: Enable PCIe Extended Tags if supported Every PCIe device can generate 5-bit transaction Tags, which allow up to 32 concurrent requests. Some devices can generate 8-bit Extended Tags, which allow up to 256 concurrent requests. Per the ECN mentioned below, all PCIe Receivers are expected to support Extended Tags, so devices are allowed (but not required) to enable them by default. If a device supports Extended Tags but does not enable them by default, enable them. This allows the device to have up to 256 outstanding transactions at a time, which may improve performance. [bhelgaas: changelog, check for PCIe device] Link: https://pcisig.com/sites/default/files/specification_documents/ECN_Extended_Tag_Enable_Default_05Sept2008_final.pdf Signed-off-by: Sinan Kaya Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index aca5b2466adb..3abc94212197 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1661,12 +1661,30 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) */ } +static void pci_configure_extended_tags(struct pci_dev *dev) +{ + u32 dev_cap; + int ret; + + if (!pci_is_pcie(dev)) + return; + + ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &dev_cap); + if (ret) + return; + + if (dev_cap & PCI_EXP_DEVCAP_EXT_TAG) + pcie_capability_set_word(dev, PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_EXT_TAG); +} + static void pci_configure_device(struct pci_dev *dev) { struct hotplug_params hpp; int ret; pci_configure_mps(dev); + pci_configure_extended_tags(dev); memset(&hpp, 0, sizeof(hpp)); ret = pci_get_hp_params(dev, &hpp); -- cgit v1.2.3 From fed678145d02d08d75825d9f0854fad93cffd1a0 Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Mon, 6 Feb 2017 13:34:14 -0200 Subject: PCI: Remove duplicate check for positive return value from probe() functions Function __pci_device_probe() tries to be careful about a PCI driver probe() hook returning a positive value, but this is not really necessary, since the same fix up is already done in local_pci_probe() (preceded by a noisy warning), which renders this instance dead code. Signed-off-by: Gabriel Krisman Bertazi Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-driver.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 1ccce1cd6aca..3e0516ee9eab 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -381,8 +381,6 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) id = pci_match_device(drv, pci_dev); if (id) error = pci_call_probe(drv, pci_dev, id); - if (error >= 0) - error = 0; } return error; } -- cgit v1.2.3