From 12b03188ab2afed784e416b4fb1366b4a6915ac0 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Mon, 6 May 2013 08:03:33 +0000 Subject: PCI: Work around Ivytown NTB BAR size issue Certain NTB devices have a hardware erratum where, regardless of pre-configured value, reading the BAR size returns 4096. To work around this issue, add a PCI quirk to read the appropriate values from an alternative register in PCI config space and move the resource endpoints to the appropriate location. Signed-off-by: Jon Mason Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7d68aeebf56b..7f492574dcf4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2865,6 +2865,31 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata); +/* + * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum. To + * work around this, query the size it should be configured to by the device and + * modify the resource end to correspond to this new size. + */ +static void quirk_intel_ntb(struct pci_dev *dev) +{ + int rc; + u8 val; + + rc = pci_read_config_byte(dev, 0x00D0, &val); + if (rc) + return; + + dev->resource[2].end = dev->resource[2].start + ((u64) 1 << val) - 1; + + rc = pci_read_config_byte(dev, 0x00D1, &val); + if (rc) + return; + + dev->resource[4].end = dev->resource[4].start + ((u64) 1 << val) - 1; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb); + static ktime_t fixup_debug_start(struct pci_dev *dev, void (*fn)(struct pci_dev *dev)) { -- cgit v1.2.1 From f6c1c8ff439ccadc333b3920c7073e0792bcb9af Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 21 Jun 2012 23:48:50 -0600 Subject: PCI/ACPI: Check acpi_resource_to_address64() return value We should check the acpi_resource_to_address64() return value, which also removes the need to validate the resource type beforehand. No functional change. Found by Coverity (CID 113815). Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1dd6f6c85874..f6c0998f248a 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -100,13 +100,12 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) { struct resource *res = data; struct acpi_resource_address64 address; + acpi_status status; - if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 && - resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 && - resource->type != ACPI_RESOURCE_TYPE_ADDRESS64) + status = acpi_resource_to_address64(resource, &address); + if (ACPI_FAILURE(status)) return AE_OK; - acpi_resource_to_address64(resource, &address); if ((address.address_length > 0) && (address.resource_type == ACPI_BUS_NUMBER_RANGE)) { res->start = address.minimum; -- cgit v1.2.1 From 2add0ec14c259471d45d6afd051ca02eef0a4a92 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 21 May 2013 10:56:51 -0600 Subject: PCI/ASPM: Warn when driver asks to disable ASPM, but we can't do it Some devices have hardware problems related to using ASPM. Drivers for these devices use pci_disable_link_state() to prevent their device from entering L0s or L1. But on platforms where the OS doesn't have permission to manage ASPM, pci_disable_link_state() doesn't actually disable ASPM. Windows has a similar mechanism ("PciASPMOptOut"), and when the OS doesn't have control of ASPM, it doesn't actually disable ASPM either. This patch just adds a warning in dmesg about the fact that pci_disable_link_state() is doing nothing. Reported-by: Emmanuel Grumbach Reference: https://lkml.kernel.org/r/CANUX_P3F5YhbZX3WGU-j1AGpbXb_T9Bis2ErhvKkFMtDvzatVQ@mail.gmail.com Reference: https://bugzilla.kernel.org/show_bug.cgi?id=57331 Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aspm.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index d320df6375a2..faa83b632a84 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -724,9 +724,6 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem, struct pci_dev *parent = pdev->bus->self; struct pcie_link_state *link; - if (aspm_disabled && !force) - return; - if (!pci_is_pcie(pdev)) return; @@ -736,6 +733,19 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem, if (!parent || !parent->link_state) return; + /* + * A driver requested that ASPM be disabled on this device, but + * if we don't have permission to manage ASPM (e.g., on ACPI + * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and + * the _OSC method), we can't honor that request. Windows has + * a similar mechanism using "PciASPMOptOut", which is also + * ignored in this situation. + */ + if (aspm_disabled && !force) { + dev_warn(&pdev->dev, "can't disable ASPM; OS doesn't have ASPM control\n"); + return; + } + if (sem) down_read(&pci_bus_sem); mutex_lock(&aspm_lock); -- cgit v1.2.1 From 33963e308e98064ce89d961ffeede2fb055f8ffc Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Sat, 25 May 2013 19:36:25 +0800 Subject: PCI: Add 0x prefix to BAR register position in __pci_read_base() We print the BAR register's position in hexadecimal format, so it is more readable if 0x prefix is added. [bhelgaas: keep dev_printk(), not dev_dbg(), so this is always in dmesg] Signed-off-by: Kevin Hao Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 70f10fa3c1b2..d40cd05bbf64 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -278,9 +278,9 @@ out: pci_write_config_word(dev, PCI_COMMAND, orig_cmd); if (bar_too_big) - dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n", pos); + dev_err(&dev->dev, "reg 0x%x: can't handle 64-bit BAR\n", pos); if (res->flags && !bar_disabled) - dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); + dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res); return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; } -- cgit v1.2.1 From 96ddef25b24a6159e78fb53c1b13336914ff1154 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Sat, 25 May 2013 19:36:26 +0800 Subject: PCI: Consolidate calls to pcibios_bus_to_resource() in __pci_read_base() Since we will invoke pcibios_bus_to_resource() unconditionally if we don't goto fail, move it out of if/else wrap. No function change. Signed-off-by: Kevin Hao Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index d40cd05bbf64..cd7b6de9376c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -250,12 +250,10 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, pci_write_config_dword(dev, pos + 4, 0); region.start = 0; region.end = sz64; - pcibios_bus_to_resource(dev, res, ®ion); bar_disabled = true; } else { region.start = l64; region.end = l64 + sz64; - pcibios_bus_to_resource(dev, res, ®ion); } } else { sz = pci_size(l, sz, mask); @@ -265,9 +263,10 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, region.start = l; region.end = l + sz; - pcibios_bus_to_resource(dev, res, ®ion); } + pcibios_bus_to_resource(dev, res, ®ion); + goto out; -- cgit v1.2.1 From cf4d1cf5ac5e7d2b886af6ed906ea0dcdc5b6855 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Sat, 25 May 2013 19:36:27 +0800 Subject: PCI: Unset resource if initial BAR value is invalid The initial BAR value in the following example is invalid: pci_bus 0000:00: root bus resource [mem 0xa0000000-0xbfffffff] (bus address [0xe0000000-0xffffffff]) pci 0000:01:00.0: reg 10: initial BAR value: 0xa0000000 pci 0000:01:00.0: reg 10: [mem 0xa0000000-0xa000007f 64bit] bus_to_resource(0xa0000000) yields 0xa0000000 because there's no host bridge window whose bus address range contains 0xa0000000. But CPU accesses to 0xa0000000 appear on the bus at 0xe0000000, so they will not be claimed if the BAR contains 0xa0000000. If we find a BAR where resource_to_bus(bus_to_resource(A)) != A, we can work around this problem by reassigning the BAR. [bhelgaas: changelog, comment] Reference: https://lkml.kernel.org/r/1368536876-27307-3-git-send-email-haokexin@gmail.com Signed-off-by: Kevin Hao Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cd7b6de9376c..fe5b50bd7536 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -170,7 +170,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, { u32 l, sz, mask; u16 orig_cmd; - struct pci_bus_region region; + struct pci_bus_region region, inverted_region; bool bar_too_big = false, bar_disabled = false; mask = type ? PCI_ROM_ADDRESS_MASK : ~0; @@ -266,6 +266,26 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, } pcibios_bus_to_resource(dev, res, ®ion); + pcibios_resource_to_bus(dev, &inverted_region, res); + + /* + * If "A" is a BAR value (a bus address), "bus_to_resource(A)" is + * the corresponding resource address (the physical address used by + * the CPU. Converting that resource address back to a bus address + * should yield the original BAR value: + * + * resource_to_bus(bus_to_resource(A)) == A + * + * If it doesn't, CPU accesses to "bus_to_resource(A)" will not + * be claimed by the device. + */ + if (inverted_region.start != region.start) { + dev_info(&dev->dev, "reg 0x%x: initial BAR value %pa invalid; forcing reassignment\n", + pos, ®ion.start); + res->flags |= IORESOURCE_UNSET; + res->end -= res->start; + res->start = 0; + } goto out; -- cgit v1.2.1 From fe830ef62ac6d8814e27b7e2f632848694b0e5c7 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 25 May 2013 21:48:29 +0800 Subject: PCI: Introduce pci_bus_{get|put}() to manage PCI bus reference count Introduce helper functions pci_bus_{get|put}() to manage PCI bus reference count. Signed-off-by: Jiang Liu Signed-off-by: Yijing Wang Signed-off-by: Gu Zheng Signed-off-by: Bjorn Helgaas --- drivers/pci/bus.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 32e66a6f12d9..b1ff02ab4f13 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -283,6 +283,21 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), } EXPORT_SYMBOL_GPL(pci_walk_bus); +struct pci_bus *pci_bus_get(struct pci_bus *bus) +{ + if (bus) + get_device(&bus->dev); + return bus; +} +EXPORT_SYMBOL(pci_bus_get); + +void pci_bus_put(struct pci_bus *bus) +{ + if (bus) + put_device(&bus->dev); +} +EXPORT_SYMBOL(pci_bus_put); + EXPORT_SYMBOL(pci_bus_alloc_resource); EXPORT_SYMBOL_GPL(pci_bus_add_device); EXPORT_SYMBOL(pci_bus_add_devices); -- cgit v1.2.1 From 3c6e6ae770f338ef3e54c5823c21063204f53537 Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Sat, 25 May 2013 21:48:30 +0800 Subject: PCI: Introduce pci_alloc_dev(struct pci_bus*) to replace alloc_pci_dev() Here we introduce a new interface to replace alloc_pci_dev(): struct pci_dev *pci_alloc_dev(struct pci_bus *bus) It takes a "struct pci_bus *" argument, so we can alloc a PCI device on a target PCI bus, and it acquires a reference on the pci_bus. We use pci_alloc_dev(NULL) to simplify the old alloc_pci_dev(), and keep it for a while but mark it as __deprecated. Holding a reference to the pci_bus ensures that referencing pci_dev->bus is valid as long as the pci_dev is valid. [bhelgaas: keep existing "return error early" structure in pci_alloc_dev()] Signed-off-by: Gu Zheng Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 70f10fa3c1b2..d47ce1400c26 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1200,7 +1200,7 @@ static void pci_release_bus_bridge_dev(struct device *dev) kfree(bridge); } -struct pci_dev *alloc_pci_dev(void) +struct pci_dev *pci_alloc_dev(struct pci_bus *bus) { struct pci_dev *dev; @@ -1210,9 +1210,16 @@ struct pci_dev *alloc_pci_dev(void) INIT_LIST_HEAD(&dev->bus_list); dev->dev.type = &pci_dev_type; + dev->bus = pci_bus_get(bus); return dev; } +EXPORT_SYMBOL(pci_alloc_dev); + +struct pci_dev *alloc_pci_dev(void) +{ + return pci_alloc_dev(NULL); +} EXPORT_SYMBOL(alloc_pci_dev); bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l, -- cgit v1.2.1 From 54a582382d997ec142a4700f9171cc28e3a9b8f6 Mon Sep 17 00:00:00 2001 From: Libo Chen Date: Mon, 27 May 2013 10:28:53 +0800 Subject: PCI: Convert ioapic.c to module_pci_driver Use module_pci_driver instead of init/exit, make code clean. Signed-off-by: Libo Chen Signed-off-by: Bjorn Helgaas --- drivers/pci/ioapic.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c index 3c6bbdd059a4..1b90579b233a 100644 --- a/drivers/pci/ioapic.c +++ b/drivers/pci/ioapic.c @@ -113,17 +113,6 @@ static struct pci_driver ioapic_driver = { .remove = ioapic_remove, }; -static int __init ioapic_init(void) -{ - return pci_register_driver(&ioapic_driver); -} - -static void __exit ioapic_exit(void) -{ - pci_unregister_driver(&ioapic_driver); -} - -module_init(ioapic_init); -module_exit(ioapic_exit); +module_pci_driver(ioapic_driver); MODULE_LICENSE("GPL"); -- cgit v1.2.1 From bb5c2de268f0d01fb3bb7683037d9b2bebcba3d5 Mon Sep 17 00:00:00 2001 From: Wang Sheng-Hui Date: Tue, 28 May 2013 11:17:41 +0800 Subject: PCI: Fix INTC comment typo for pci_swizzle_interrupt_pin() The INTx pin should be INIT[ABCD]. Fix the typo "3=INTC". Signed-off-by: Wang Sheng-Hui Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a899d8bb190d..e5f4e55d407d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2421,7 +2421,7 @@ bool pci_acs_path_enabled(struct pci_dev *start, /** * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge * @dev: the PCI device - * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD) + * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) * * Perform INTx swizzling for a device behind one level of bridge. This is * required by section 9.1 of the PCI-to-PCI bridge specification for devices -- cgit v1.2.1 From 2dfca877b3c599ec081c23939b34ee22576e0833 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 28 May 2013 16:03:22 +0800 Subject: PCI: Fix kerneldoc for pci_disable_link_state() Fix kerneldoc for pci_disable_link_state(). [bhelgaas: expand comment, fix typos] Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aspm.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index faa83b632a84..403a44374ed5 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -714,10 +714,6 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev) up_read(&pci_bus_sem); } -/* - * pci_disable_link_state - disable pci device's link state, so the link will - * never enter specific states - */ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem, bool force) { @@ -771,6 +767,15 @@ void pci_disable_link_state_locked(struct pci_dev *pdev, int state) } EXPORT_SYMBOL(pci_disable_link_state_locked); +/** + * pci_disable_link_state - Disable device's link state, so the link will + * never enter specific states. Note that if the BIOS didn't grant ASPM + * control to the OS, this does nothing because we can't touch the LNKCTL + * register. + * + * @pdev: PCI device + * @state: ASPM link state to disable + */ void pci_disable_link_state(struct pci_dev *pdev, int state) { __pci_disable_link_state(pdev, state, true, false); -- cgit v1.2.1 From e7d4515209db5246245eb5667a94ad86ba9a12cc Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 28 May 2013 16:03:46 +0800 Subject: PCI: Replace printks with appropriate pr_*() Replace deprecated printk(KERN_ERR...) with pr_err() in pci-acpi.c Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index e4b1fb2c0f5d..6c15d6a96935 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -376,12 +376,12 @@ static int __init acpi_pci_init(void) int ret; if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_MSI) { - printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n"); + pr_info("ACPI FADT declares the system doesn't support MSI, so disable it\n"); pci_no_msi(); } if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { - printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); + pr_info("ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); pcie_no_aspm(); } -- cgit v1.2.1 From 65f6ae66a6fb44f614a1226c398fcb38e94b3c59 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 13 May 2013 11:05:48 +0200 Subject: PCI: Allocate only as many MSI vectors as requested by driver Because of the encoding of the "Multiple Message Capable" and "Multiple Message Enable" fields, a device can only advertise that it's capable of a power-of-two number of vectors, and the OS can only enable a power-of-two number. For example, a device that's limited internally to using 18 vectors would have to advertise that it's capable of 32. The 14 extra vectors consume vector numbers and IRQ descriptors even though the device can't actually use them. This fix introduces a 'msi_desc::nvec_used' field to address this issue. When non-zero, it is the actual number of MSIs the device will send, as requested by the device driver. This value should be used by architectures to set up and tear down only as many interrupt resources as the device will actually use. Note, although the existing 'msi_desc::multiple' field might seem redundant, in fact it is not. The number of MSIs advertised need not be the smallest power-of-two larger than the number of MSIs the device will send. Thus, it is not always possible to derive the former from the latter, so we need to keep them both to handle this case. [bhelgaas: changelog, rename to "nvec_used"] Signed-off-by: Alexander Gordeev Signed-off-by: Bjorn Helgaas --- drivers/pci/msi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 2c1075213bec..aca7578b05e5 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -81,7 +81,10 @@ void default_teardown_msi_irqs(struct pci_dev *dev) int i, nvec; if (entry->irq == 0) continue; - nvec = 1 << entry->msi_attrib.multiple; + if (entry->nvec_used) + nvec = entry->nvec_used; + else + nvec = 1 << entry->msi_attrib.multiple; for (i = 0; i < nvec; i++) arch_teardown_msi_irq(entry->irq + i); } @@ -336,7 +339,10 @@ static void free_msi_irqs(struct pci_dev *dev) int i, nvec; if (!entry->irq) continue; - nvec = 1 << entry->msi_attrib.multiple; + if (entry->nvec_used) + nvec = entry->nvec_used; + else + nvec = 1 << entry->msi_attrib.multiple; #ifdef CONFIG_GENERIC_HARDIRQS for (i = 0; i < nvec; i++) BUG_ON(irq_has_action(entry->irq + i)); -- cgit v1.2.1 From 516ca22307df6ba972e9719ec756a356187cdde7 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 28 May 2013 18:04:46 -0600 Subject: PCI/ACPI: Combine duplicate adjacent "if" tests [bhelgaas: split out from acpi_pci_roots removal] Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1dd6f6c85874..eb09053c0fce 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -536,11 +536,10 @@ static int acpi_pci_root_add(struct acpi_device *device, if (system_state != SYSTEM_BOOTING) { pcibios_resource_survey_bus(root->bus); pci_assign_unassigned_bus_resources(root->bus); - } - /* need to after hot-added ioapic is registered */ - if (system_state != SYSTEM_BOOTING) + /* need to after hot-added ioapic is registered */ pci_enable_bridges(root->bus); + } pci_bus_add_devices(root->bus); return 1; -- cgit v1.2.1 From bfe2414aecca03d884f680d5cf1d612c7813ee33 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 28 May 2013 18:31:27 -0600 Subject: PCI/ACPI: Introduce "handle" local for economy of expression [bhelgaas: split out from acpi_handle_printk() changes] Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index eb09053c0fce..852fb96f94e5 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -382,13 +382,14 @@ static int acpi_pci_root_add(struct acpi_device *device, int result; struct acpi_pci_root *root; u32 flags, base_flags; + acpi_handle handle = device->handle; root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); if (!root) return -ENOMEM; segment = 0; - status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL, + status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segment); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { printk(KERN_ERR PREFIX "can't evaluate _SEG\n"); @@ -398,7 +399,7 @@ static int acpi_pci_root_add(struct acpi_device *device, /* Check _CRS first, then _BBN. If no _BBN, default to zero. */ root->secondary.flags = IORESOURCE_BUS; - status = try_get_root_bridge_busnr(device->handle, &root->secondary); + status = try_get_root_bridge_busnr(handle, &root->secondary); if (ACPI_FAILURE(status)) { /* * We need both the start and end of the downstream bus range @@ -409,7 +410,7 @@ static int acpi_pci_root_add(struct acpi_device *device, root->secondary.end = 0xFF; printk(KERN_WARNING FW_BUG PREFIX "no secondary bus range in _CRS\n"); - status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, + status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &bus); if (ACPI_SUCCESS(status)) root->secondary.start = bus; @@ -433,7 +434,7 @@ static int acpi_pci_root_add(struct acpi_device *device, acpi_device_name(device), acpi_device_bid(device), root->segment, &root->secondary); - root->mcfg_addr = acpi_pci_root_get_mcfg_addr(device->handle); + root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle); /* * All supported architectures that use ACPI have support for @@ -502,7 +503,7 @@ static int acpi_pci_root_add(struct acpi_device *device, dev_info(&device->dev, "Requesting ACPI _OSC control (0x%02x)\n", flags); - status = acpi_pci_osc_control_set(device->handle, &flags, + status = acpi_pci_osc_control_set(handle, &flags, OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); if (ACPI_SUCCESS(status)) { dev_info(&device->dev, -- cgit v1.2.1 From bbebed6423f5b281f9ca314518531f90424f6f57 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 28 May 2013 17:59:25 -0600 Subject: PCI/ACPI: Remove unused global list acpi_pci_roots Now the global list acpi_pci_roots pci_root.c is useless, remove it. Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki Cc: Len Brown --- drivers/acpi/pci_root.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 852fb96f94e5..18b7ab2dee4f 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -65,10 +65,6 @@ static struct acpi_scan_handler pci_root_handler = { .detach = acpi_pci_root_remove, }; -/* Lock to protect both acpi_pci_roots lists */ -static DEFINE_MUTEX(acpi_pci_root_lock); -static LIST_HEAD(acpi_pci_roots); - static DEFINE_MUTEX(osc_lock); /** @@ -423,7 +419,6 @@ static int acpi_pci_root_add(struct acpi_device *device, } } - INIT_LIST_HEAD(&root->node); root->device = device; root->segment = segment & 0xFFFF; strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); @@ -447,10 +442,6 @@ static int acpi_pci_root_add(struct acpi_device *device, * TBD: Need PCI interface for enumeration/configuration of roots. */ - mutex_lock(&acpi_pci_root_lock); - list_add_tail(&root->node, &acpi_pci_roots); - mutex_unlock(&acpi_pci_root_lock); - /* * Scan the Root Bridge * -------------------- @@ -464,7 +455,7 @@ static int acpi_pci_root_add(struct acpi_device *device, "Bus %04x:%02x not present in PCI namespace\n", root->segment, (unsigned int)root->secondary.start); result = -ENODEV; - goto out_del_root; + goto end; } /* Indicate support for various _OSC capabilities. */ @@ -545,11 +536,6 @@ static int acpi_pci_root_add(struct acpi_device *device, pci_bus_add_devices(root->bus); return 1; -out_del_root: - mutex_lock(&acpi_pci_root_lock); - list_del(&root->node); - mutex_unlock(&acpi_pci_root_lock); - end: kfree(root); return result; @@ -566,9 +552,6 @@ static void acpi_pci_root_remove(struct acpi_device *device) pci_remove_root_bus(root->bus); - mutex_lock(&acpi_pci_root_lock); - list_del(&root->node); - mutex_unlock(&acpi_pci_root_lock); kfree(root); } -- cgit v1.2.1 From 6dc7d22c67384d313fca88c1a63af3220a2beff7 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 28 May 2013 18:10:05 -0600 Subject: PCI/ACPI: Use dev_printk(), acpi_handle_print(), pr_xxx() when possible Use dev_printk(), acpi_handle_print(), and pr_xxx() to print messages in pci_root.c. [bhelgaas: fold in dev_printk() changes, use dev_printk() in handle_root_bridge_insertion()] Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki Cc: Len Brown --- drivers/acpi/pci_root.c | 59 ++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 18b7ab2dee4f..27020882eb97 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -388,7 +388,7 @@ static int acpi_pci_root_add(struct acpi_device *device, status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segment); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { - printk(KERN_ERR PREFIX "can't evaluate _SEG\n"); + dev_err(&device->dev, "can't evaluate _SEG\n"); result = -ENODEV; goto end; } @@ -404,8 +404,8 @@ static int acpi_pci_root_add(struct acpi_device *device, * can do is assume [_BBN-0xFF] or [0-0xFF]. */ root->secondary.end = 0xFF; - printk(KERN_WARNING FW_BUG PREFIX - "no secondary bus range in _CRS\n"); + dev_warn(&device->dev, + FW_BUG "no secondary bus range in _CRS\n"); status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &bus); if (ACPI_SUCCESS(status)) @@ -413,7 +413,7 @@ static int acpi_pci_root_add(struct acpi_device *device, else if (status == AE_NOT_FOUND) root->secondary.start = 0; else { - printk(KERN_ERR PREFIX "can't evaluate _BBN\n"); + dev_err(&device->dev, "can't evaluate _BBN\n"); result = -ENODEV; goto end; } @@ -425,7 +425,7 @@ static int acpi_pci_root_add(struct acpi_device *device, strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); device->driver_data = root; - printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n", + pr_info(PREFIX "%s [%s] (domain %04x %pR)\n", acpi_device_name(device), acpi_device_bid(device), root->segment, &root->secondary); @@ -451,9 +451,9 @@ static int acpi_pci_root_add(struct acpi_device *device, */ root->bus = pci_acpi_scan_root(root); if (!root->bus) { - printk(KERN_ERR PREFIX - "Bus %04x:%02x not present in PCI namespace\n", - root->segment, (unsigned int)root->secondary.start); + dev_err(&device->dev, + "Bus %04x:%02x not present in PCI namespace\n", + root->segment, (unsigned int)root->secondary.start); result = -ENODEV; goto end; } @@ -511,8 +511,8 @@ static int acpi_pci_root_add(struct acpi_device *device, "ACPI _OSC request failed (%s), " "returned control mask: 0x%02x\n", acpi_format_exception(status), flags); - pr_info("ACPI _OSC control for PCIe not granted, " - "disabling ASPM\n"); + dev_info(&device->dev, + "ACPI _OSC control for PCIe not granted, disabling ASPM\n"); pcie_no_aspm(); } } else { @@ -571,12 +571,13 @@ static void handle_root_bridge_insertion(acpi_handle handle) struct acpi_device *device; if (!acpi_bus_get_device(handle, &device)) { - printk(KERN_DEBUG "acpi device exists...\n"); + dev_printk(KERN_DEBUG, &device->dev, + "acpi device already exists; ignoring notify\n"); return; } if (acpi_bus_scan(handle)) - printk(KERN_ERR "cannot add bridge to acpi list\n"); + acpi_handle_err(handle, "cannot add bridge to acpi list\n"); } static void handle_root_bridge_removal(struct acpi_device *device) @@ -605,7 +606,6 @@ static void handle_root_bridge_removal(struct acpi_device *device) static void _handle_hotplug_event_root(struct work_struct *work) { struct acpi_pci_root *root; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER }; struct acpi_hp_work *hp_work; acpi_handle handle; u32 type; @@ -617,13 +617,12 @@ static void _handle_hotplug_event_root(struct work_struct *work) acpi_scan_lock_acquire(); root = acpi_pci_find_root(handle); - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus enumerate */ - printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__, - (char *)buffer.pointer); + acpi_handle_printk(KERN_DEBUG, handle, + "Bus check notify on %s\n", __func__); if (!root) handle_root_bridge_insertion(handle); @@ -631,28 +630,28 @@ static void _handle_hotplug_event_root(struct work_struct *work) case ACPI_NOTIFY_DEVICE_CHECK: /* device check */ - printk(KERN_DEBUG "%s: Device check notify on %s\n", __func__, - (char *)buffer.pointer); + acpi_handle_printk(KERN_DEBUG, handle, + "Device check notify on %s\n", __func__); if (!root) handle_root_bridge_insertion(handle); break; case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ - printk(KERN_DEBUG "%s: Device eject notify on %s\n", __func__, - (char *)buffer.pointer); + acpi_handle_printk(KERN_DEBUG, handle, + "Device eject notify on %s\n", __func__); if (root) handle_root_bridge_removal(root->device); break; default: - printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n", - type, (char *)buffer.pointer); + acpi_handle_warn(handle, + "notify_handler: unknown event type 0x%x\n", + type); break; } acpi_scan_lock_release(); kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ - kfree(buffer.pointer); } static void handle_hotplug_event_root(acpi_handle handle, u32 type, @@ -666,9 +665,6 @@ static acpi_status __init find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; int *count = (int *)context; if (!acpi_is_root_bridge(handle)) @@ -676,16 +672,15 @@ find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) (*count)++; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_root, NULL); if (ACPI_FAILURE(status)) - printk(KERN_DEBUG "acpi root: %s notify handler is not installed, exit status: %u\n", - objname, (unsigned int)status); + acpi_handle_printk(KERN_DEBUG, handle, + "notify handler is not installed, exit status: %u\n", + (unsigned int)status); else - printk(KERN_DEBUG "acpi root: %s notify handler is installed\n", - objname); + acpi_handle_printk(KERN_DEBUG, handle, + "notify handler is installed\n"); return AE_OK; } -- cgit v1.2.1 From fbf33f516bdbcc2ab1ba1e54dfb720b0cfaa6874 Mon Sep 17 00:00:00 2001 From: Xudong Hao Date: Fri, 31 May 2013 12:21:29 +0800 Subject: PCI: Finish SR-IOV VF setup before adding the device Commit 4f535093cf "PCI: Put pci_dev in device tree as early as possible" moves device registering from pci_bus_add_devices() to pci_device_add(). That causes problems for virtual functions because device_add(&virtfn->dev) is called before setting the virtfn->is_virtfn flag, which then causes Xen to report PCI virtual functions as PCI physical functions. Fix it by setting virtfn->is_virtfn before calling pci_device_add(). [Jiang Liu]: Move the setting of virtfn->is_virtfn ahead further for better readability and modify changelog. Signed-off-by: Xudong Hao Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org # v3.9+ --- drivers/pci/iov.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index c93071d428f5..a971a6f6268d 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -92,6 +92,8 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device); pci_setup_device(virtfn); virtfn->dev.parent = dev->dev.parent; + virtfn->physfn = pci_dev_get(dev); + virtfn->is_virtfn = 1; for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { res = dev->resource + PCI_IOV_RESOURCES + i; @@ -113,9 +115,6 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) pci_device_add(virtfn, virtfn->bus); mutex_unlock(&iov->dev->sriov->lock); - virtfn->physfn = pci_dev_get(dev); - virtfn->is_virtfn = 1; - rc = pci_bus_add_device(virtfn); sprintf(buf, "virtfn%u", id); rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); -- cgit v1.2.1 From 9a994e8ec7e7d6b1a66c74a683596b0f38f4e345 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Sat, 1 Jun 2013 16:25:25 +0900 Subject: PCI: Replace strict_strtoul() with kstrtoul() The usage of strict_strtoul() is not preferred, because strict_strtoul() is obsolete. Thus, kstrtoul() should be used. [bhelgaas: "#define strict_strtoul kstrtoul", so no functional change] Signed-off-by: Jingoo Han Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5b4a9d9cd200..0b56e0865f38 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -66,7 +66,7 @@ static ssize_t broken_parity_status_store(struct device *dev, struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; pdev->broken_parity_status = !!val; @@ -188,7 +188,7 @@ static ssize_t is_enabled_store(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - ssize_t result = strict_strtoul(buf, 0, &val); + ssize_t result = kstrtoul(buf, 0, &val); if (result < 0) return result; @@ -259,7 +259,7 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; /* bad things may happen if the no_msi flag is changed @@ -291,7 +291,7 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, unsigned long val; struct pci_bus *b = NULL; - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; if (val) { @@ -315,7 +315,7 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr, unsigned long val; struct pci_dev *pdev = to_pci_dev(dev); - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; if (val) { @@ -342,7 +342,7 @@ remove_store(struct device *dev, struct device_attribute *dummy, int ret = 0; unsigned long val; - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; /* An attribute cannot be unregistered by one of its own methods, @@ -362,7 +362,7 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr, unsigned long val; struct pci_bus *bus = to_pci_bus(dev); - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; if (val) { @@ -384,7 +384,7 @@ static ssize_t d3cold_allowed_store(struct device *dev, struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - if (strict_strtoul(buf, 0, &val) < 0) + if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; pdev->d3cold_allowed = !!val; @@ -1236,7 +1236,7 @@ static ssize_t reset_store(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - ssize_t result = strict_strtoul(buf, 0, &val); + ssize_t result = kstrtoul(buf, 0, &val); if (result < 0) return result; -- cgit v1.2.1 From fafe5c3d82a470d73de53e6b08eb4e28d974d895 Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Mon, 3 Jun 2013 18:24:10 +0800 Subject: ahci: Add AMD CZ SATA device ID To add AMD CZ SATA controller device ID of IDE mode. [bhelgaas: drop pci_ids.h update] Signed-off-by: Shane Huang Signed-off-by: Bjorn Helgaas Reviewed-by: Tejun Heo Cc: stable@vger.kernel.org --- drivers/ata/ahci.c | 1 + drivers/pci/quirks.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 251e57d38942..98496600a15a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -310,6 +310,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { /* AMD */ { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */ + { PCI_VDEVICE(AMD, 0x7900), board_ahci }, /* AMD CZ */ /* AMD is using RAID class only for ahci controllers */ { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci }, diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7d68aeebf56b..df4655c5c138 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1022,6 +1022,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE, quirk_amd_ide_mode); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x7900, quirk_amd_ide_mode); +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, 0x7900, quirk_amd_ide_mode); /* * Serverworks CSB5 IDE does not fully support native mode -- cgit v1.2.1 From b996ac90f595dda271cbd858b136b45557fc1a57 Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Mon, 3 Jun 2013 18:24:55 +0800 Subject: i2c-piix4: Add AMD CZ SMBus device ID To add AMD CZ SMBus controller device ID. [bhelgaas: drop pci_ids.h update] Signed-off-by: Shane Huang Signed-off-by: Bjorn Helgaas Reviewed-by: Tejun Heo Reviewed-by: Jean Delvare Cc: stable@vger.kernel.org --- drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-piix4.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 631736e2e7ed..4faf02b3657d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -150,6 +150,7 @@ config I2C_PIIX4 ATI SB700/SP5100 ATI SB800 AMD Hudson-2 + AMD CZ Serverworks OSB4 Serverworks CSB5 Serverworks CSB6 diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 39ab78c1a02c..d05ad590af29 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -22,7 +22,7 @@ Intel PIIX4, 440MX Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100 ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800 - AMD Hudson-2 + AMD Hudson-2, CZ SMSC Victory66 Note: we assume there can only be one device, with one or more @@ -522,6 +522,7 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x790b) }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4) }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, -- cgit v1.2.1 From 5fec945105448b958b8418b7e5d043d630ec3155 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 13 May 2013 11:06:17 +0200 Subject: x86/MSI: Conserve interrupt resources when using multiple-MSIs Current multiple-MSI implementation does not take into account actual number of requested MSIs and always rounds that number to a larger power-of-two value. Yet, the number of MSIs a PCI device could send (and therefore the number of messages a device driver could request) may be smaller. As result, resources allocated for extra MSIs are just wasted. This update takes advantage of 'msi_desc::nvec_used' field introduced with generic MSI code to track the number of requested and used MSIs. As result, resources associated with interrupts are conserved. Of those resources most noticeable are x86 interrupt vectors. The initial version of this fix also conserved IRTEs, but Jan noticed that a malfunctioning PCI device might send a message number it did not claim and thus refer to an IRTE it does not own. To avoid this security hole, as many IRTEs are reserved as the device could possibly send. [bhelgaas: changelog, rename to "nvec_used"] Signed-off-by: Alexander Gordeev Signed-off-by: Bjorn Helgaas --- drivers/iommu/irq_remapping.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index dcfea4e39be7..39f81aeefcd6 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -51,26 +51,27 @@ static void irq_remapping_disable_io_apic(void) static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) { - int node, ret, sub_handle, index = 0; + int node, ret, sub_handle, nvec_pow2, index = 0; unsigned int irq; struct msi_desc *msidesc; - nvec = __roundup_pow_of_two(nvec); - WARN_ON(!list_is_singular(&dev->msi_list)); msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); WARN_ON(msidesc->irq); WARN_ON(msidesc->msi_attrib.multiple); + WARN_ON(msidesc->nvec_used); node = dev_to_node(&dev->dev); irq = __create_irqs(get_nr_irqs_gsi(), nvec, node); if (irq == 0) return -ENOSPC; - msidesc->msi_attrib.multiple = ilog2(nvec); + nvec_pow2 = __roundup_pow_of_two(nvec); + msidesc->nvec_used = nvec; + msidesc->msi_attrib.multiple = ilog2(nvec_pow2); for (sub_handle = 0; sub_handle < nvec; sub_handle++) { if (!sub_handle) { - index = msi_alloc_remapped_irq(dev, irq, nvec); + index = msi_alloc_remapped_irq(dev, irq, nvec_pow2); if (index < 0) { ret = index; goto error; @@ -95,6 +96,7 @@ error: * IRQs from tearing down again in default_teardown_msi_irqs() */ msidesc->irq = 0; + msidesc->nvec_used = 0; msidesc->msi_attrib.multiple = 0; return ret; -- cgit v1.2.1 From 6ae32c539c0412ca789fb6041be45eeabf78431c Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 4 Jun 2013 19:18:14 +0200 Subject: PCI: Add pcibios_release_device() Platforms may want to provide architecture-specific functionality when a PCI device is released. Add a pcibios_release_device() call that architectures can override to do so. Signed-off-by: Sebastian Ott Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 10 ++++++++++ drivers/pci/probe.c | 1 + 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e5f4e55d407d..709791b70ca0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1334,6 +1334,16 @@ int __weak pcibios_add_device (struct pci_dev *dev) return 0; } +/** + * pcibios_release_device - provide arch specific hooks when releasing device dev + * @dev: the PCI device being released + * + * Permits the platform to provide architecture specific functionality when + * devices are released. This is the default implementation. Architecture + * implementations can override this. + */ +void __weak pcibios_release_device(struct pci_dev *dev) {} + /** * pcibios_disable_device - disable arch specific PCI resources for device dev * @dev: the PCI device to disable diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 70f10fa3c1b2..58cc0a8a0979 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1132,6 +1132,7 @@ static void pci_release_dev(struct device *dev) pci_dev = to_pci_dev(dev); pci_release_capabilities(pci_dev); pci_release_of_node(pci_dev); + pcibios_release_device(pci_dev); kfree(pci_dev); } -- cgit v1.2.1 From dfab88beda88d6c24111e5966b08ecf813c3a18a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Fri, 31 May 2013 12:21:31 +0800 Subject: PCI: Hide remove and rescan sysfs interfaces for SR-IOV virtual functions PCI devices for SR-IOV virtual functions should only be created/ destroyed by pci_enable_sriov()/pci_disable_sriov() because special data structures are associated with SR-IOV virtual functions. So hide hotplug related sysfs interfaces "remove" and "rescan" for SR-IOV virtual functions, otherwise it may cause memory leakage and other issues. Signed-off-by: Jiang Liu Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas Cc: Donald Dutile Cc: Yinghai Lu Cc: Ram Pai --- drivers/pci/pci-sysfs.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5b4a9d9cd200..403da60cd983 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -325,6 +325,8 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr, } return count; } +struct device_attribute dev_rescan_attr = __ATTR(rescan, (S_IWUSR|S_IWGRP), + NULL, dev_rescan_store); static void remove_callback(struct device *dev) { @@ -354,6 +356,8 @@ remove_store(struct device *dev, struct device_attribute *dummy, count = ret; return count; } +struct device_attribute dev_remove_attr = __ATTR(remove, (S_IWUSR|S_IWGRP), + NULL, remove_store); static ssize_t dev_bus_rescan_store(struct device *dev, struct device_attribute *attr, @@ -504,8 +508,6 @@ struct device_attribute pci_dev_attrs[] = { __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), broken_parity_status_show,broken_parity_status_store), __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store), - __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store), - __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store), #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI) __ATTR(d3cold_allowed, 0644, d3cold_allowed_show, d3cold_allowed_store), #endif @@ -1463,6 +1465,29 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj, return a->mode; } +static struct attribute *pci_dev_hp_attrs[] = { + &dev_remove_attr.attr, + &dev_rescan_attr.attr, + NULL, +}; + +static umode_t pci_dev_hp_attrs_are_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct pci_dev *pdev = to_pci_dev(dev); + + if (pdev->is_virtfn) + return 0; + + return a->mode; +} + +static struct attribute_group pci_dev_hp_attr_group = { + .attrs = pci_dev_hp_attrs, + .is_visible = pci_dev_hp_attrs_are_visible, +}; + #ifdef CONFIG_PCI_IOV static struct attribute *sriov_dev_attrs[] = { &sriov_totalvfs_attr.attr, @@ -1494,6 +1519,7 @@ static struct attribute_group pci_dev_attr_group = { static const struct attribute_group *pci_dev_attr_groups[] = { &pci_dev_attr_group, + &pci_dev_hp_attr_group, #ifdef CONFIG_PCI_IOV &sriov_dev_attr_group, #endif -- cgit v1.2.1 From 8b1fce04dc2a2210f050484afa85acc3a81cfbba Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Sat, 25 May 2013 21:48:31 +0800 Subject: PCI: Convert alloc_pci_dev(void) to pci_alloc_dev(bus) Use the new pci_alloc_dev(bus) to replace the existing using of alloc_pci_dev(void). [bhelgaas: drop pci_bus ref later in pci_release_dev()] Signed-off-by: Gu Zheng Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: "David S. Miller" Cc: David Airlie Cc: Neela Syam Kolli Cc: "James E.J. Bottomley" Cc: Yinghai Lu Cc: Greg Kroah-Hartman Cc: Andrew Morton --- drivers/char/agp/alpha-agp.c | 2 +- drivers/char/agp/parisc-agp.c | 2 +- drivers/pci/iov.c | 8 +++++--- drivers/pci/probe.c | 5 +++-- drivers/scsi/megaraid.c | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c index dd84af4d4f7e..199b8e99f7d7 100644 --- a/drivers/char/agp/alpha-agp.c +++ b/drivers/char/agp/alpha-agp.c @@ -174,7 +174,7 @@ alpha_core_agp_setup(void) /* * Build a fake pci_dev struct */ - pdev = alloc_pci_dev(); + pdev = pci_alloc_dev(NULL); if (!pdev) return -ENOMEM; pdev->vendor = 0xffff; diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index 94821ab01c6d..bf5d2477cb77 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -333,7 +333,7 @@ parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa) struct agp_bridge_data *bridge; int error = 0; - fake_bridge_dev = alloc_pci_dev(); + fake_bridge_dev = pci_alloc_dev(NULL); if (!fake_bridge_dev) { error = -ENOMEM; goto fail; diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index c93071d428f5..2652ca00fae7 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -75,18 +75,20 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) struct pci_dev *virtfn; struct resource *res; struct pci_sriov *iov = dev->sriov; + struct pci_bus *bus; - virtfn = alloc_pci_dev(); + virtfn = pci_alloc_dev(NULL); if (!virtfn) return -ENOMEM; mutex_lock(&iov->dev->sriov->lock); - virtfn->bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id)); - if (!virtfn->bus) { + bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id)); + if (!bus) { kfree(virtfn); mutex_unlock(&iov->dev->sriov->lock); return -ENOMEM; } + virtfn->bus = pci_bus_get(bus); virtfn->devfn = virtfn_devfn(dev, id); virtfn->vendor = dev->vendor; pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index d47ce1400c26..ed5ce185eed9 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1132,6 +1132,7 @@ static void pci_release_dev(struct device *dev) pci_dev = to_pci_dev(dev); pci_release_capabilities(pci_dev); pci_release_of_node(pci_dev); + pci_bus_put(pci_dev->bus); kfree(pci_dev); } @@ -1270,11 +1271,10 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000)) return NULL; - dev = alloc_pci_dev(); + dev = pci_alloc_dev(bus); if (!dev) return NULL; - dev->bus = bus; dev->devfn = devfn; dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; @@ -1282,6 +1282,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) pci_set_of_node(dev); if (pci_setup_device(dev)) { + pci_bus_put(dev->bus); kfree(dev); return NULL; } diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 846f475f62c1..90c95a3385d1 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -2026,7 +2026,7 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) static inline int make_local_pdev(adapter_t *adapter, struct pci_dev **pdev) { - *pdev = alloc_pci_dev(); + *pdev = pci_alloc_dev(NULL); if( *pdev == NULL ) return -1; -- cgit v1.2.1 From 8b8d2b658f2cb7092672a56c72b41121ce786d93 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 6 Jun 2013 12:10:46 -0600 Subject: PCI/AER: Don't parse HEST table for non-PCIe devices AER is a PCIe-only capability, so there's no point in trying to match a HEST PCIe structure with a non-PCIe device. Previously, a HEST global AER bridge entry (type 8) could incorrectly match *any* bridge, even a legacy PCI-PCI bridge, and a non-global HEST entry could match a legacy PCI device. Tested-by: Betty Dall Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer/aerdrv_acpi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 5194a7d41730..4f798ab629c8 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -59,8 +59,7 @@ static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data) p = (struct acpi_hest_aer_common *)(hest_hdr + 1); if (p->flags & ACPI_HEST_GLOBAL) { - if ((pci_is_pcie(info->pci_dev) && - pci_pcie_type(info->pci_dev) == pcie_type) || bridge) + if ((pci_pcie_type(info->pci_dev) == pcie_type) || bridge) ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); } else if (hest_match_pci(p, info->pci_dev)) @@ -89,6 +88,9 @@ static void aer_set_firmware_first(struct pci_dev *pci_dev) int pcie_aer_get_firmware_first(struct pci_dev *dev) { + if (!pci_is_pcie(dev)) + return 0; + if (!dev->__aer_firmware_first_valid) aer_set_firmware_first(dev); return dev->__aer_firmware_first; -- cgit v1.2.1 From a6bd73cdc93ec03781ff99beb5b465fd6ea3a784 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 6 Jun 2013 12:10:47 -0600 Subject: PCI/AER: Factor out HEST device type matching This factors out the matching of HEST structure type and PCIe device type to improve readability. No functional change. Tested-by: Betty Dall Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer/aerdrv_acpi.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 4f798ab629c8..e7ea5735a61f 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -29,6 +29,22 @@ static inline int hest_match_pci(struct acpi_hest_aer_common *p, p->function == PCI_FUNC(pci->devfn)); } +static inline bool hest_match_type(struct acpi_hest_header *hest_hdr, + struct pci_dev *dev) +{ + u16 hest_type = hest_hdr->type; + u8 pcie_type = pci_pcie_type(dev); + + if ((hest_type == ACPI_HEST_TYPE_AER_ROOT_PORT && + pcie_type == PCI_EXP_TYPE_ROOT_PORT) || + (hest_type == ACPI_HEST_TYPE_AER_ENDPOINT && + pcie_type == PCI_EXP_TYPE_ENDPOINT) || + (hest_type == ACPI_HEST_TYPE_AER_BRIDGE && + (dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)) + return true; + return false; +} + struct aer_hest_parse_info { struct pci_dev *pci_dev; int firmware_first; @@ -38,28 +54,11 @@ static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data) { struct aer_hest_parse_info *info = data; struct acpi_hest_aer_common *p; - u8 pcie_type = 0; - u8 bridge = 0; int ff = 0; - switch (hest_hdr->type) { - case ACPI_HEST_TYPE_AER_ROOT_PORT: - pcie_type = PCI_EXP_TYPE_ROOT_PORT; - break; - case ACPI_HEST_TYPE_AER_ENDPOINT: - pcie_type = PCI_EXP_TYPE_ENDPOINT; - break; - case ACPI_HEST_TYPE_AER_BRIDGE: - if ((info->pci_dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) - bridge = 1; - break; - default: - return 0; - } - p = (struct acpi_hest_aer_common *)(hest_hdr + 1); if (p->flags & ACPI_HEST_GLOBAL) { - if ((pci_pcie_type(info->pci_dev) == pcie_type) || bridge) + if (hest_match_type(hest_hdr, info->pci_dev)) ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); } else if (hest_match_pci(p, info->pci_dev)) -- cgit v1.2.1 From 8d2a171f18f7cc9271ee3b9f1355fa4a13380320 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 6 Jun 2013 12:10:48 -0600 Subject: PCI/AER: Set dev->__aer_firmware_first only for matching devices Previously, we always updated info->firmware_first, even for HEST entries that didn't match the device. Therefore, if the last HEST descriptor was a PCIe structure that didn't match the device, we always cleared dev->__aer_firmware_first. Tested-by: Betty Dall Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer/aerdrv_acpi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index e7ea5735a61f..cf611ab2193a 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -54,16 +54,16 @@ static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data) { struct aer_hest_parse_info *info = data; struct acpi_hest_aer_common *p; - int ff = 0; + int ff; p = (struct acpi_hest_aer_common *)(hest_hdr + 1); + ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); if (p->flags & ACPI_HEST_GLOBAL) { if (hest_match_type(hest_hdr, info->pci_dev)) - ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); + info->firmware_first = ff; } else if (hest_match_pci(p, info->pci_dev)) - ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); - info->firmware_first = ff; + info->firmware_first = ff; return 0; } -- cgit v1.2.1 From 9e50a9122f048c67a4e83916434e2e212a6f0fe2 Mon Sep 17 00:00:00 2001 From: Betty Dall Date: Thu, 6 Jun 2013 12:10:49 -0600 Subject: PCI/AER: Move AER severity defines to aer.h The function aer_recover_queue() is a public interface and the severity argument uses #defines that are in the private header pci/pcie/aer/aerdrv.h. This patch moves the #defines from pci/pcie/aer/aerdrv.h to include/linux/aer.h. [bhelgaas: split "remove 'extern' from declarations" to another patch] Signed-off-by: Betty Dall Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer/aerdrv.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index d12c77cd6991..90ea3e88041f 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -13,10 +13,6 @@ #include #include -#define AER_NONFATAL 0 -#define AER_FATAL 1 -#define AER_CORRECTABLE 2 - #define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \ PCI_EXP_RTCTL_SENFEE| \ PCI_EXP_RTCTL_SEFEE) -- cgit v1.2.1 From 0ba98ec9196746dd6abfa7bb9856ef4f29ffb9be Mon Sep 17 00:00:00 2001 From: Betty Dall Date: Thu, 6 Jun 2013 12:10:50 -0600 Subject: ACPI / APEI: Force fatal AER severity when component has been reset The CPER error record has a reset bit that indicates that the platform has reset the component. The reset bit can be set for any severity error including recoverable. From the AER code path's perspective, any error is fatal if the component has been reset. This patch upgrades the severity of the AER recovery to AER_FATAL whenever the CPER error record indicates that the component has been reset. [bhelgaas: s/bus has been reset/component has been reset/] Signed-off-by: Betty Dall Signed-off-by: Bjorn Helgaas --- drivers/acpi/apei/ghes.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index d668a8ae602b..ab315515908e 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -449,9 +449,19 @@ static void ghes_do_proc(struct ghes *ghes, pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { unsigned int devfn; int aer_severity; + devfn = PCI_DEVFN(pcie_err->device_id.device, pcie_err->device_id.function); aer_severity = cper_severity_to_aer(sev); + + /* + * If firmware reset the component to contain + * the error, we must reinitialize it before + * use, so treat it as a fatal AER error. + */ + if (gdata->flags & CPER_SEC_RESET) + aer_severity = AER_FATAL; + aer_recover_queue(pcie_err->device_id.segment, pcie_err->device_id.bus, devfn, aer_severity); -- cgit v1.2.1 From 081d0fe0ef60c258b67428a8fdf2d14f8ce392ef Mon Sep 17 00:00:00 2001 From: Betty Dall Date: Thu, 6 Jun 2013 12:10:51 -0600 Subject: PCI/AER: Reset link for devices below Root Port or Downstream Port When a PCIe device reports a fatal error, we reset the link leading to it. Previously we only did this for devices below Downstream Ports, not for devices directly below Root Ports. This patch changes that so we reset the link leading to devices below Root Ports just like we do for those below Downstream Ports. [bhelgaas: changelog, keep dev_printk(KERN_DEBUG)] Signed-off-by: Betty Dall Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer/aerdrv_core.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 8ec8b4f48560..d9e776e69fe8 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -400,16 +400,16 @@ void aer_do_secondary_bus_reset(struct pci_dev *dev) } /** - * default_downstream_reset_link - default reset function for Downstream Port - * @dev: pointer to downstream port's pci_dev data structure + * default_reset_link - default reset function + * @dev: pointer to pci_dev data structure * - * Invoked when performing link reset at Downstream Port w/ no aer driver. + * Invoked when performing link reset on a Downstream Port or a + * Root Port with no aer driver. */ -static pci_ers_result_t default_downstream_reset_link(struct pci_dev *dev) +static pci_ers_result_t default_reset_link(struct pci_dev *dev) { aer_do_secondary_bus_reset(dev); - dev_printk(KERN_DEBUG, &dev->dev, - "Downstream Port link has been reset\n"); + dev_printk(KERN_DEBUG, &dev->dev, "downstream link has been reset\n"); return PCI_ERS_RESULT_RECOVERED; } @@ -458,8 +458,9 @@ static pci_ers_result_t reset_link(struct pci_dev *dev) if (driver && driver->reset_link) { status = driver->reset_link(udev); - } else if (pci_pcie_type(udev) == PCI_EXP_TYPE_DOWNSTREAM) { - status = default_downstream_reset_link(udev); + } else if (pci_pcie_type(udev) == PCI_EXP_TYPE_DOWNSTREAM || + pci_pcie_type(udev) == PCI_EXP_TYPE_ROOT_PORT) { + status = default_reset_link(udev); } else { dev_printk(KERN_DEBUG, &dev->dev, "no link-reset support at upstream device %s\n", -- cgit v1.2.1 From 343df771e671d821478dd3ef525a0610b808dbf8 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Fri, 7 Jun 2013 01:10:08 +0800 Subject: PCI: Fix refcount issue in pci_create_root_bus() error recovery path After calling device_register(&bridge->dev), the bridge is reference- counted, and it is illegal to call kfree() on it except in the release function. [bhelgaas: changelog, use put_device() after device_register() failure] Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org --- drivers/pci/probe.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ed5ce185eed9..15c39cb09619 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1711,12 +1711,16 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, bridge->dev.release = pci_release_bus_bridge_dev; dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); error = pcibios_root_bridge_prepare(bridge); - if (error) - goto bridge_dev_reg_err; + if (error) { + kfree(bridge); + goto err_out; + } error = device_register(&bridge->dev); - if (error) - goto bridge_dev_reg_err; + if (error) { + put_device(&bridge->dev); + goto err_out; + } b->bridge = get_device(&bridge->dev); device_enable_async_suspend(b->bridge); pci_set_bus_of_node(b); @@ -1772,8 +1776,6 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, class_dev_reg_err: put_device(&bridge->dev); device_unregister(&bridge->dev); -bridge_dev_reg_err: - kfree(bridge); err_out: kfree(b); return NULL; -- cgit v1.2.1 From 70efde2a2920c12f2b14eb640944ca7e61b2c02d Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Fri, 7 Jun 2013 16:16:51 -0600 Subject: PCI: Rename pci_release_bus_bridge_dev() to pci_release_host_bridge_dev() This renames pci_release_bus_bridge_dev() to pci_release_host_bridge_dev() and moves it next to pci_alloc_host_bridge(). No functional change. [bhelgaas: split rename & move out of create/destroy symmetry patch] Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 15c39cb09619..a723b2b93ab4 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -468,6 +468,18 @@ static struct pci_bus * pci_alloc_bus(void) return b; } +static void pci_release_host_bridge_dev(struct device *dev) +{ + struct pci_host_bridge *bridge = to_pci_host_bridge(dev); + + if (bridge->release_fn) + bridge->release_fn(bridge); + + pci_free_resource_list(&bridge->windows); + + kfree(bridge); +} + static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b) { struct pci_host_bridge *bridge; @@ -1189,18 +1201,6 @@ int pci_cfg_space_size(struct pci_dev *dev) return PCI_CFG_SPACE_SIZE; } -static void pci_release_bus_bridge_dev(struct device *dev) -{ - struct pci_host_bridge *bridge = to_pci_host_bridge(dev); - - if (bridge->release_fn) - bridge->release_fn(bridge); - - pci_free_resource_list(&bridge->windows); - - kfree(bridge); -} - struct pci_dev *pci_alloc_dev(struct pci_bus *bus) { struct pci_dev *dev; @@ -1708,7 +1708,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, goto err_out; bridge->dev.parent = parent; - bridge->dev.release = pci_release_bus_bridge_dev; + bridge->dev.release = pci_release_host_bridge_dev; dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); error = pcibios_root_bridge_prepare(bridge); if (error) { -- cgit v1.2.1 From bd0c50240b71a69ba6cc690797e2371002cd241c Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 9 Jun 2013 11:47:49 +0800 Subject: PCI: Fix comment typo for pcie_pme_remove() Fix trivial comment typo for pcie_pme_remove(). Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/pme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 795db1f9d50c..e56e594ce112 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -408,7 +408,7 @@ static int pcie_pme_resume(struct pcie_device *srv) /** * pcie_pme_remove - Prepare PCIe PME service device for removal. - * @srv - PCIe service device to resume. + * @srv - PCIe service device to remove. */ static void pcie_pme_remove(struct pcie_device *srv) { -- cgit v1.2.1 From fc6504b3a4dc9beae782a11e6f7c3c4a9f077fb8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 14 Jun 2013 00:29:50 +0200 Subject: PCI / ACPI / PM: Use correct power state strings in messages Make acpi_pci_set_power_state() print the name of the ACPI device power state the device has been actually put into instead of printing the name of the requested PCI device power state, which need not be the same. [bhelgaas: use ACPI_STATE_D3_COLD (ACPI_STATE_D3 == ACPI_STATE_D3_COLD)] Signed-off-by: Rafael J. Wysocki Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 6c15d6a96935..dbdc5f7e2b29 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -186,8 +186,8 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) [PCI_D0] = ACPI_STATE_D0, [PCI_D1] = ACPI_STATE_D1, [PCI_D2] = ACPI_STATE_D2, - [PCI_D3hot] = ACPI_STATE_D3, - [PCI_D3cold] = ACPI_STATE_D3 + [PCI_D3hot] = ACPI_STATE_D3_COLD, + [PCI_D3cold] = ACPI_STATE_D3_COLD, }; int error = -EINVAL; @@ -211,7 +211,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) if (!error) dev_info(&dev->dev, "power state changed by ACPI to %s\n", - pci_power_name(state)); + acpi_power_state_string(state_conv[state])); return error; } -- cgit v1.2.1 From d35329d9f17f05277f2718eb54402dea3e833d19 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 25 May 2013 21:48:36 +0800 Subject: PCI: Drop redundant setting of bus->is_added in virtfn_add_bus() The flag pci_bus->is_added is used to guard invocation of pcibios_fixup_bus(pci_bus). When virtfn_add_bus() is called, the pci_bus->is_added flag has already been set, so remove the redundant bus->is_added = 1; Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas Cc: Donald Dutile Cc: Yinghai Lu Cc: Ram Pai --- drivers/pci/iov.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 2652ca00fae7..8f1e1174b71f 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -47,7 +47,6 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) return NULL; pci_bus_insert_busn_res(child, busnr, busnr); - bus->is_added = 1; return child; } -- cgit v1.2.1 From dc087f2f6a2925e81831f3016b9cbb6e470e7423 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 25 May 2013 21:48:37 +0800 Subject: PCI: Simplify IOV implementation and fix reference count races Trivial changes to IOV: 1) use new PCI interfaces to simplify IOV implementation 2) fix some reference count related race windows [bhelgaas: fix virtfn_add() add bus/alloc dev error paths] Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas Cc: Donald Dutile Cc: Yinghai Lu Cc: Ram Pai --- drivers/pci/iov.c | 59 ++++++++++++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 8f1e1174b71f..5fffca995a91 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -51,24 +51,16 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) return child; } -static void virtfn_remove_bus(struct pci_bus *bus, int busnr) +static void virtfn_remove_bus(struct pci_bus *physbus, struct pci_bus *virtbus) { - struct pci_bus *child; - - if (bus->number == busnr) - return; - - child = pci_find_bus(pci_domain_nr(bus), busnr); - BUG_ON(!child); - - if (list_empty(&child->devices)) - pci_remove_bus(child); + if (physbus != virtbus && list_empty(&virtbus->devices)) + pci_remove_bus(virtbus); } static int virtfn_add(struct pci_dev *dev, int id, int reset) { int i; - int rc; + int rc = -ENOMEM; u64 size; char buf[VIRTFN_ID_LEN]; struct pci_dev *virtfn; @@ -76,18 +68,15 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) struct pci_sriov *iov = dev->sriov; struct pci_bus *bus; - virtfn = pci_alloc_dev(NULL); - if (!virtfn) - return -ENOMEM; - mutex_lock(&iov->dev->sriov->lock); bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id)); - if (!bus) { - kfree(virtfn); - mutex_unlock(&iov->dev->sriov->lock); - return -ENOMEM; - } - virtfn->bus = pci_bus_get(bus); + if (!bus) + goto failed; + + virtfn = pci_alloc_dev(bus); + if (!virtfn) + goto failed0; + virtfn->devfn = virtfn_devfn(dev, id); virtfn->vendor = dev->vendor; pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device); @@ -136,7 +125,9 @@ failed1: pci_dev_put(dev); mutex_lock(&iov->dev->sriov->lock); pci_stop_and_remove_bus_device(virtfn); - virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); +failed0: + virtfn_remove_bus(dev->bus, bus); +failed: mutex_unlock(&iov->dev->sriov->lock); return rc; @@ -145,20 +136,15 @@ failed1: static void virtfn_remove(struct pci_dev *dev, int id, int reset) { char buf[VIRTFN_ID_LEN]; - struct pci_bus *bus; struct pci_dev *virtfn; struct pci_sriov *iov = dev->sriov; - bus = pci_find_bus(pci_domain_nr(dev->bus), virtfn_bus(dev, id)); - if (!bus) - return; - - virtfn = pci_get_slot(bus, virtfn_devfn(dev, id)); + virtfn = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus), + virtfn_bus(dev, id), + virtfn_devfn(dev, id)); if (!virtfn) return; - pci_dev_put(virtfn); - if (reset) { device_release_driver(&virtfn->dev); __pci_reset_function(virtfn); @@ -176,9 +162,11 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset) mutex_lock(&iov->dev->sriov->lock); pci_stop_and_remove_bus_device(virtfn); - virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); + virtfn_remove_bus(dev->bus, virtfn->bus); mutex_unlock(&iov->dev->sriov->lock); + /* balance pci_get_domain_bus_and_slot() */ + pci_dev_put(virtfn); pci_dev_put(dev); } @@ -335,13 +323,14 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) if (!pdev) return -ENODEV; - pci_dev_put(pdev); - - if (!pdev->is_physfn) + if (!pdev->is_physfn) { + pci_dev_put(pdev); return -ENODEV; + } rc = sysfs_create_link(&dev->dev.kobj, &pdev->dev.kobj, "dep_link"); + pci_dev_put(pdev); if (rc) return rc; } -- cgit v1.2.1 From 050134864c1c76f49eb86c134a0e02fb3c196382 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 5 Jun 2013 14:22:11 -0600 Subject: PCI: Return early on allocation failures to unindent mainline code On allocation failure, return early so the main body of the function doesn't have to be indented as the body of an "if" statement. No functional change. Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a723b2b93ab4..14af6ef4959c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -451,20 +451,21 @@ void pci_read_bridge_bases(struct pci_bus *child) } } -static struct pci_bus * pci_alloc_bus(void) +static struct pci_bus *pci_alloc_bus(void) { struct pci_bus *b; b = kzalloc(sizeof(*b), GFP_KERNEL); - if (b) { - INIT_LIST_HEAD(&b->node); - INIT_LIST_HEAD(&b->children); - INIT_LIST_HEAD(&b->devices); - INIT_LIST_HEAD(&b->slots); - INIT_LIST_HEAD(&b->resources); - b->max_bus_speed = PCI_SPEED_UNKNOWN; - b->cur_bus_speed = PCI_SPEED_UNKNOWN; - } + if (!b) + return NULL; + + INIT_LIST_HEAD(&b->node); + INIT_LIST_HEAD(&b->children); + INIT_LIST_HEAD(&b->devices); + INIT_LIST_HEAD(&b->slots); + INIT_LIST_HEAD(&b->resources); + b->max_bus_speed = PCI_SPEED_UNKNOWN; + b->cur_bus_speed = PCI_SPEED_UNKNOWN; return b; } @@ -485,11 +486,11 @@ static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b) struct pci_host_bridge *bridge; bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); - if (bridge) { - INIT_LIST_HEAD(&bridge->windows); - bridge->bus = b; - } + if (!bridge) + return NULL; + INIT_LIST_HEAD(&bridge->windows); + bridge->bus = b; return bridge; } -- cgit v1.2.1 From 728cdb7582a230234795619036d887d7f52bce1e Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 18 Jun 2013 16:22:14 +0800 Subject: PCI: Use pdev->pm_cap instead of pci_find_capability(..,PCI_CAP_ID_PM) PCI PM cap register offset has been saved in pci_pm_init(), so we can use pdev->pm_cap instead of using pci_find_capability(..) here. Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/pci/pci.c | 2 +- drivers/pci/quirks.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 709791b70ca0..e37fea6e178d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -805,7 +805,7 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { pci_power_t ret; - if (!pci_find_capability(dev, PCI_CAP_ID_PM)) + if (!dev->pm_cap) return PCI_D0; ret = platform_pci_choose_state(dev); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7f492574dcf4..dee5ed4f7b6e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1832,7 +1832,6 @@ static void quirk_e100_interrupt(struct pci_dev *dev) u16 command, pmcsr; u8 __iomem *csr; u8 cmd_hi; - int pm; switch (dev->device) { /* PCI IDs taken from drivers/net/e100.c */ @@ -1870,9 +1869,8 @@ static void quirk_e100_interrupt(struct pci_dev *dev) * Check that the device is in the D0 power state. If it's not, * there is no point to look any further. */ - pm = pci_find_capability(dev, PCI_CAP_ID_PM); - if (pm) { - pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); + if (dev->pm_cap) { + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) return; } -- cgit v1.2.1