From 1778794031aae75d4464904319d320edc3e77d39 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 30 Oct 2012 14:31:10 -0600 Subject: PCI: Separate out pci_assign_unassigned_bus_resources() It is main portion of pci_rescan_bus(). Separate it out and prepare to use it for PCI root bus hot add later. Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/pci/setup-bus.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 1e808ca338f8..f64c071d6923 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1550,25 +1550,12 @@ enable_all: } EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); -#ifdef CONFIG_HOTPLUG -/** - * pci_rescan_bus - scan a PCI bus for devices. - * @bus: PCI bus to scan - * - * Scan a PCI bus and child buses for new devices, adds them, - * and enables them. - * - * Returns the max number of subordinate bus discovered. - */ -unsigned int __ref pci_rescan_bus(struct pci_bus *bus) +void pci_assign_unassigned_bus_resources(struct pci_bus *bus) { - unsigned int max; struct pci_dev *dev; LIST_HEAD(add_list); /* list of resources that want additional resources */ - max = pci_scan_child_bus(bus); - down_read(&pci_bus_sem); list_for_each_entry(dev, &bus->devices, bus_list) if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || @@ -1581,6 +1568,24 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus) BUG_ON(!list_empty(&add_list)); pci_enable_bridges(bus); +} + +#ifdef CONFIG_HOTPLUG +/** + * pci_rescan_bus - scan a PCI bus for devices. + * @bus: PCI bus to scan + * + * Scan a PCI bus and child buses for new devices, adds them, + * and enables them. + * + * Returns the max number of subordinate bus discovered. + */ +unsigned int __ref pci_rescan_bus(struct pci_bus *bus) +{ + unsigned int max; + + max = pci_scan_child_bus(bus); + pci_assign_unassigned_bus_resources(bus); pci_bus_add_devices(bus); return max; -- cgit v1.2.1 From a5213a3194f73cd29c68128d1540ce81f03ba7b9 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 30 Oct 2012 14:31:21 -0600 Subject: PCI: Move pci_rescan_bus() back to probe.c We have pci_assign_unassigned_bus_resources() in as global function now. Move pci_rescan_bus() back to probe.c where it should be. Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 21 +++++++++++++++++++++ drivers/pci/setup-bus.c | 23 ----------------------- 2 files changed, 21 insertions(+), 23 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ec909afa90b6..65f62e353719 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1890,6 +1890,27 @@ unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge) return max; } +/** + * pci_rescan_bus - scan a PCI bus for devices. + * @bus: PCI bus to scan + * + * Scan a PCI bus and child buses for new devices, adds them, + * and enables them. + * + * Returns the max number of subordinate bus discovered. + */ +unsigned int __ref pci_rescan_bus(struct pci_bus *bus) +{ + unsigned int max; + + max = pci_scan_child_bus(bus); + pci_assign_unassigned_bus_resources(bus); + pci_bus_add_devices(bus); + + return max; +} +EXPORT_SYMBOL_GPL(pci_rescan_bus); + EXPORT_SYMBOL(pci_add_new_bus); EXPORT_SYMBOL(pci_scan_slot); EXPORT_SYMBOL(pci_scan_bridge); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index f64c071d6923..59e6c55c6d25 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1569,26 +1569,3 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus) pci_enable_bridges(bus); } - -#ifdef CONFIG_HOTPLUG -/** - * pci_rescan_bus - scan a PCI bus for devices. - * @bus: PCI bus to scan - * - * Scan a PCI bus and child buses for new devices, adds them, - * and enables them. - * - * Returns the max number of subordinate bus discovered. - */ -unsigned int __ref pci_rescan_bus(struct pci_bus *bus) -{ - unsigned int max; - - max = pci_scan_child_bus(bus); - pci_assign_unassigned_bus_resources(bus); - pci_bus_add_devices(bus); - - return max; -} -EXPORT_SYMBOL_GPL(pci_rescan_bus); -#endif -- cgit v1.2.1 From e164f658f209b85566732bd85c62009237be0909 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 30 Oct 2012 14:31:26 -0600 Subject: PCI: Move out pci_enable_bridges out of assign_unsigned_bus_res So could use assign_unassigned_bus_res pci root bus add Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 1 + drivers/pci/setup-bus.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 65f62e353719..59cf1ba34936 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1905,6 +1905,7 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus) max = pci_scan_child_bus(bus); pci_assign_unassigned_bus_resources(bus); + pci_enable_bridges(bus); pci_bus_add_devices(bus); return max; diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 59e6c55c6d25..6d3591d57ea0 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1566,6 +1566,4 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus) up_read(&pci_bus_sem); __pci_bus_assign_resources(bus, &add_list, NULL); BUG_ON(!list_empty(&add_list)); - - pci_enable_bridges(bus); } -- cgit v1.2.1 From cdfcc572be0a8b423cecfb4ab5fd735fafe9c54a Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 30 Oct 2012 14:31:38 -0600 Subject: PCI: Add pci_stop_and_remove_root_bus() It supports both PCI root bus and PCI bus under PCI bridge. Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/pci/remove.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 513972f3ed13..7c0fd9252e6f 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -111,3 +111,39 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev) pci_remove_bus_device(dev); } EXPORT_SYMBOL(pci_stop_and_remove_bus_device); + +void pci_stop_root_bus(struct pci_bus *bus) +{ + struct pci_dev *child, *tmp; + struct pci_host_bridge *host_bridge; + + if (!pci_is_root_bus(bus)) + return; + + host_bridge = to_pci_host_bridge(bus->bridge); + list_for_each_entry_safe_reverse(child, tmp, + &bus->devices, bus_list) + pci_stop_bus_device(child); + + /* stop the host bridge */ + device_del(&host_bridge->dev); +} + +void pci_remove_root_bus(struct pci_bus *bus) +{ + struct pci_dev *child, *tmp; + struct pci_host_bridge *host_bridge; + + if (!pci_is_root_bus(bus)) + return; + + host_bridge = to_pci_host_bridge(bus->bridge); + list_for_each_entry_safe(child, tmp, + &bus->devices, bus_list) + pci_remove_bus_device(child); + pci_remove_bus(bus); + host_bridge->bus = NULL; + + /* remove the host bridge */ + put_device(&host_bridge->dev); +} -- cgit v1.2.1 From 642c92da36ae0bed3c31fdd408411ab95f4e326b Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Tue, 30 Oct 2012 15:26:18 +0900 Subject: PCI: Don't pass pci_dev to pci_ext_cfg_avail() pci_ext_cfg_avail() doesn't use the "struct pci_dev *" passed to it, and there's no requirement that a host bridge even be represented by a pci_dev. This drops the pci_ext_cfg_avail() parameter. [bhelgaas: changelog] Signed-off-by: Taku Izumi Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 54858838f098..01b68bfa2321 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3833,14 +3833,13 @@ static void __devinit pci_no_domains(void) } /** - * pci_ext_cfg_enabled - can we access extended PCI config space? - * @dev: The PCI device of the root bridge. + * pci_ext_cfg_avail - can we access extended PCI config space? * * Returns 1 if we can access PCI extended config space (offsets * greater than 0xff). This is the default implementation. Architecture * implementations can override this. */ -int __weak pci_ext_cfg_avail(struct pci_dev *dev) +int __weak pci_ext_cfg_avail(void) { return 1; } -- cgit v1.2.1 From 42eca2302146fed51335b95128e949ee6f54478f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 29 Oct 2012 17:26:54 -0600 Subject: PCI: Don't touch card regs after runtime suspend D3 If the driver takes care of state saving, don't touch any registers on it. Optimus (dual-gpu) laptops seem to have their own form of D3cold, but unfortunately enter it on normal D3 transitions via the ACPI callback. So when we use runtime PM to transition to D3, the card disappears off the PCI bus, however we then try to access registers on it in the runtime suspend finish, which really doesn't work. This patch checks whether the pci state is saved and doesn't attempt to hit any registers after that point if it is. (Looks okay to Rafael) Signed-off-by: Dave Airlie Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-driver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 94c6e2aa03d6..11d9c8a9d0d0 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1023,10 +1023,10 @@ static int pci_pm_runtime_suspend(struct device *dev) return 0; } - if (!pci_dev->state_saved) + if (!pci_dev->state_saved) { pci_save_state(pci_dev); - - pci_finish_runtime_suspend(pci_dev); + pci_finish_runtime_suspend(pci_dev); + } return 0; } -- cgit v1.2.1 From 438be3c6b76fa129731a320ec7f0bb3d530bcb50 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 28 Oct 2012 01:05:49 -0700 Subject: PCI: Convert dev_printk(KERN_ to dev_( dev_ calls take less code than dev_printk(KERN_ and reducing object size is good. Coalesce formats for easier grep. Signed-off-by: Joe Perches Signed-off-by: Bjorn Helgaas --- drivers/pci/irq.c | 10 +++++----- drivers/pci/pci-stub.c | 2 +- drivers/pci/pcie/aspm.c | 7 ++----- 3 files changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/irq.c b/drivers/pci/irq.c index e5f69a43b1b1..b008cf86b9c3 100644 --- a/drivers/pci/irq.c +++ b/drivers/pci/irq.c @@ -14,11 +14,11 @@ static void pci_note_irq_problem(struct pci_dev *pdev, const char *reason) { struct pci_dev *parent = to_pci_dev(pdev->dev.parent); - dev_printk(KERN_ERR, &pdev->dev, - "Potentially misrouted IRQ (Bridge %s %04x:%04x)\n", - dev_name(&parent->dev), parent->vendor, parent->device); - dev_printk(KERN_ERR, &pdev->dev, "%s\n", reason); - dev_printk(KERN_ERR, &pdev->dev, "Please report to linux-kernel@vger.kernel.org\n"); + dev_err(&pdev->dev, + "Potentially misrouted IRQ (Bridge %s %04x:%04x)\n", + dev_name(&parent->dev), parent->vendor, parent->device); + dev_err(&pdev->dev, "%s\n", reason); + dev_err(&pdev->dev, "Please report to linux-kernel@vger.kernel.org\n"); WARN_ON(1); } diff --git a/drivers/pci/pci-stub.c b/drivers/pci/pci-stub.c index 775e933c2225..6e47c519c510 100644 --- a/drivers/pci/pci-stub.c +++ b/drivers/pci/pci-stub.c @@ -28,7 +28,7 @@ MODULE_PARM_DESC(ids, "Initial PCI IDs to add to the stub driver, format is " static int pci_stub_probe(struct pci_dev *dev, const struct pci_device_id *id) { - dev_printk(KERN_INFO, &dev->dev, "claimed by stub\n"); + dev_info(&dev->dev, "claimed by stub\n"); return 0; } diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 213753b283a6..3da9ecc9ab84 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -242,8 +242,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) return; /* Training failed. Restore common clock configurations */ - dev_printk(KERN_ERR, &parent->dev, - "ASPM: Could not configure common clock\n"); + dev_err(&parent->dev, "ASPM: Could not configure common clock\n"); list_for_each_entry(child, &linkbus->devices, bus_list) pcie_capability_write_word(child, PCI_EXP_LNKCTL, child_reg[PCI_FUNC(child->devfn)]); @@ -507,9 +506,7 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) */ pcie_capability_read_dword(child, PCI_EXP_DEVCAP, ®32); if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) { - dev_printk(KERN_INFO, &child->dev, "disabling ASPM" - " on pre-1.1 PCIe device. You can enable it" - " with 'pcie_aspm=force'\n"); + dev_info(&child->dev, "disabling ASPM on pre-1.1 PCIe device. You can enable it with 'pcie_aspm=force'\n"); return -EINVAL; } } -- cgit v1.2.1 From 21c5fd97380ba22c2a616b482307b2ef94429f31 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Tue, 30 Oct 2012 17:25:53 +0000 Subject: PCI: Add workaround for PLX PCI 9050 BAR alignment erratum The PLX PCI 9050 PCI Target bridge controller has a bug that prevents its local configuration registers being read through BAR0 (memory) or BAR1 (i/o) if the base address lies on an odd 128-byte boundary, i.e. if bit 7 of the base address is non-zero. This bug is described in the PCI 9050 errata list, version 1.4, May 2005. It was fixed in the pin-compatible PCI 9052, which can be distinguished from the PCI 9050 by checking the revision in the PCI header, which is hard-coded for these chips. Workaround the problem by re-allocating the affected regions to a 256-byte boundary. Note that BAR0 and/or BAR1 may have been disabled (size 0) during initialization of the PCI chip when its configuration is read from a serial EEPROM. Currently, the fix-up has only been used for devices with the default vendor and device ID of the PLX PCI 9050. The PCI 9052 shares the same default device ID as the PCI 9050 but they have different PCI revision codes. Signed-off-by: Ian Abbott Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7a451ff56ecc..2d0d1c229c68 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1790,6 +1790,34 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE, quirk_tc86c001_ide); +/* + * PLX PCI 9050 PCI Target bridge controller has an errata that prevents the + * local configuration registers accessible via BAR0 (memory) or BAR1 (i/o) + * being read correctly if bit 7 of the base address is set. + * The BAR0 or BAR1 region may be disabled (size 0) or enabled (size 128). + * Re-allocate the regions to a 256-byte boundary if necessary. + */ +static void __devinit quirk_plx_pci9050(struct pci_dev *dev) +{ + unsigned int bar; + + /* Fixed in revision 2 (PCI 9052). */ + if (dev->revision >= 2) + return; + for (bar = 0; bar <= 1; bar++) + if (pci_resource_len(dev, bar) == 0x80 && + (pci_resource_start(dev, bar) & 0x80)) { + struct resource *r = &dev->resource[bar]; + dev_info(&dev->dev, + "Re-allocating PLX PCI 9050 BAR %u to length 256 to avoid bit 7 bug\n", + bar); + r->start = 0; + r->end = 0xff; + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + quirk_plx_pci9050); + static void __devinit quirk_netmos(struct pci_dev *dev) { unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4; -- cgit v1.2.1 From 2794bb28b66b61eca15ffc492463001445a47227 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Mon, 29 Oct 2012 14:40:18 +0000 Subject: PCI: Add PLX PCI 9050 workaround for some Meilhaus DAQ cards The Meilhaus ME-2000i and ME-2600i data acquisition cards supported by the Comedi "me_daq" driver use the PLX PCI 9050 PCI Target bridge chip affected by the bug that prevents the chip's local configuration registers being read from BAR0 or BAR1 base addresses that are an odd multiple of 128 bytes. Use the PLX PCI 9050 quirk handler for these devices to re-allocate affected regions to a 256-byte boundary. Signed-off-by: Ian Abbott Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 2d0d1c229c68..0c59f7aba12b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1817,6 +1817,17 @@ static void __devinit quirk_plx_pci9050(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, quirk_plx_pci9050); +/* + * The following Meilhaus (vendor ID 0x1402) device IDs (amongst others) + * may be using the PLX PCI 9050: 0x0630, 0x0940, 0x0950, 0x0960, 0x100b, + * 0x1400, 0x140a, 0x140b, 0x14e0, 0x14ea, 0x14eb, 0x1604, 0x1608, 0x160c, + * 0x168f, 0x2000, 0x2600, 0x3000, 0x810a, 0x810b. + * + * Currently, device IDs 0x2000 and 0x2600 are used by the Comedi "me_daq" + * driver. + */ +DECLARE_PCI_FIXUP_HEADER(0x1402, 0x2000, quirk_plx_pci9050); +DECLARE_PCI_FIXUP_HEADER(0x1402, 0x2600, quirk_plx_pci9050); static void __devinit quirk_netmos(struct pci_dev *dev) { -- cgit v1.2.1 From 6e965e0d0e1d102c261326b06338d3385ea55f97 Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Fri, 26 Oct 2012 13:07:51 +0800 Subject: PCI/PM: Add comments for PME poll support for PCIe There are comments on why PME poll support is necessary for PCI devices, but not for PCIe devices. That may lead to misunderstanding that PME poll is only necessary for PCI devices. So add comments related to PCIe PME poll to make it more clear. The content of comments comes from the changelog of commit: 379021d5c0899fcf9410cae4ca7a59a5a94ca769 Signed-off-by: Huang Ying Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/pci/pci.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 54858838f098..485cfa9af2ef 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1578,15 +1578,25 @@ void pci_pme_active(struct pci_dev *dev, bool enable) pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr); - /* PCI (as opposed to PCIe) PME requires that the device have - its PME# line hooked up correctly. Not all hardware vendors - do this, so the PME never gets delivered and the device - remains asleep. The easiest way around this is to - periodically walk the list of suspended devices and check - whether any have their PME flag set. The assumption is that - we'll wake up often enough anyway that this won't be a huge - hit, and the power savings from the devices will still be a - win. */ + /* + * PCI (as opposed to PCIe) PME requires that the device have + * its PME# line hooked up correctly. Not all hardware vendors + * do this, so the PME never gets delivered and the device + * remains asleep. The easiest way around this is to + * periodically walk the list of suspended devices and check + * whether any have their PME flag set. The assumption is that + * we'll wake up often enough anyway that this won't be a huge + * hit, and the power savings from the devices will still be a + * win. + * + * Although PCIe uses in-band PME message instead of PME# line + * to report PME, PME does not work for some PCIe devices in + * reality. For example, there are devices that set their PME + * status bits, but don't really bother to send a PME message; + * there are PCI Express Root Ports that don't bother to + * trigger interrupts when they receive PME messages from the + * devices below. So PME poll is used for PCIe devices too. + */ if (dev->pme_poll) { struct pci_pme_device *pme_dev; -- cgit v1.2.1 From 4e15c46bdc4d5ea0e7991a05edbd807328d38a2c Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 5 Nov 2012 15:20:34 -0500 Subject: PCI: Add pci_device_type to pdev's device struct Need type filled in device structure so it can be used for visible attribute control in sysfs for pci_dev. Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 24 ++++++++++++++++++++++++ drivers/pci/pci.h | 1 + drivers/pci/probe.c | 1 + 3 files changed, 26 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 02d107b15281..3d160aa608c1 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1411,3 +1411,27 @@ static int __init pci_sysfs_init(void) } late_initcall(pci_sysfs_init); + +static struct attribute *pci_dev_dev_attrs[] = { + NULL, +}; + +static umode_t pci_dev_attrs_are_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + return a->mode; +} + +static struct attribute_group pci_dev_attr_group = { + .attrs = pci_dev_dev_attrs, + .is_visible = pci_dev_attrs_are_visible, +}; + +static const struct attribute_group *pci_dev_attr_groups[] = { + &pci_dev_attr_group, + NULL, +}; + +struct device_type pci_dev_type = { + .groups = pci_dev_attr_groups, +}; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index bacbcba69cf3..6f6cd145bb7e 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -157,6 +157,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev) } extern struct device_attribute pci_dev_attrs[]; extern struct device_attribute pcibus_dev_attrs[]; +extern struct device_type pci_dev_type; #ifdef CONFIG_HOTPLUG extern struct bus_attribute pci_bus_attrs[]; #else diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ec909afa90b6..0312f1c48b3c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -975,6 +975,7 @@ int pci_setup_device(struct pci_dev *dev) dev->sysdata = dev->bus->sysdata; dev->dev.parent = dev->bus->bridge; dev->dev.bus = &pci_bus_type; + dev->dev.type = &pci_dev_type; dev->hdr_type = hdr_type & 0x7f; dev->multifunction = !!(hdr_type & 0x80); dev->error_state = pci_channel_io_normal; -- cgit v1.2.1 From 625e1d59a89f50bace376f429d8cf50347af75f7 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 5 Nov 2012 15:20:35 -0500 Subject: PCI: Use is_visible() with boot_vga attribute for pci_dev Should make pci_create_sysfs_dev_files() simpler. Also fix possible memleak in remove path. Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 3d160aa608c1..fbbb97f28259 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1303,29 +1303,20 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) pdev->rom_attr = attr; } - if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { - retval = device_create_file(&pdev->dev, &vga_attr); - if (retval) - goto err_rom_file; - } - /* add platform-specific attributes */ retval = pcibios_add_platform_entries(pdev); if (retval) - goto err_vga_file; + goto err_rom_file; /* add sysfs entries for various capabilities */ retval = pci_create_capabilities_sysfs(pdev); if (retval) - goto err_vga_file; + goto err_rom_file; pci_create_firmware_label_files(pdev); return 0; -err_vga_file: - if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) - device_remove_file(&pdev->dev, &vga_attr); err_rom_file: if (rom_size) { sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); @@ -1413,12 +1404,20 @@ static int __init pci_sysfs_init(void) late_initcall(pci_sysfs_init); static struct attribute *pci_dev_dev_attrs[] = { + &vga_attr.attr, NULL, }; static umode_t pci_dev_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 (a == &vga_attr.attr) + if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) + return 0; + return a->mode; } -- cgit v1.2.1 From 1789382a72a537447d65ea4131d8bcc1ad85ce7b Mon Sep 17 00:00:00 2001 From: Donald Dutile Date: Mon, 5 Nov 2012 15:20:36 -0500 Subject: PCI: SRIOV control and status via sysfs Provide files under sysfs to determine the maximum number of VFs an SR-IOV-capable PCIe device supports, and methods to enable and disable the VFs on a per-device basis. Currently, VF enablement by SR-IOV-capable PCIe devices is done via driver-specific module parameters. If not setup in modprobe files, it requires admin to unload & reload PF drivers with number of desired VFs to enable. Additionally, the enablement is system wide: all devices controlled by the same driver have the same number of VFs enabled. Although the latter is probably desired, there are PCI configurations setup by system BIOS that may not enable that to occur. Two files are created for the PF of PCIe devices with SR-IOV support: sriov_totalvfs Contains the maximum number of VFs the device could support as reported by the TotalVFs register in the SR-IOV extended capability. sriov_numvfs Contains the number of VFs currently enabled on this device as reported by the NumVFs register in the SR-IOV extended capability. Writing zero to this file disables all VFs. Writing a positive number to this file enables that number of VFs. These files are readable for all SR-IOV PF devices. Writes to the sriov_numvfs file are effective only if a driver that supports the sriov_configure() method is attached. Signed-off-by: Donald Dutile Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index fbbb97f28259..74508c63bd47 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -404,6 +404,106 @@ static ssize_t d3cold_allowed_show(struct device *dev, } #endif +#ifdef CONFIG_PCI_IOV +static ssize_t sriov_totalvfs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return sprintf(buf, "%u\n", pdev->sriov->total); +} + + +static ssize_t sriov_numvfs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return sprintf(buf, "%u\n", pdev->sriov->nr_virtfn); +} + +/* + * num_vfs > 0; number of vfs to enable + * num_vfs = 0; disable all vfs + * + * Note: SRIOV spec doesn't allow partial VF + * disable, so its all or none. + */ +static ssize_t sriov_numvfs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int num_vfs_enabled = 0; + int num_vfs; + int ret = 0; + u16 total; + + if (kstrtoint(buf, 0, &num_vfs) < 0) + return -EINVAL; + + /* is PF driver loaded w/callback */ + if (!pdev->driver || !pdev->driver->sriov_configure) { + dev_info(&pdev->dev, + "Driver doesn't support SRIOV configuration via sysfs\n"); + return -ENOSYS; + } + + /* if enabling vf's ... */ + total = pdev->sriov->total; + /* Requested VFs to enable < totalvfs and none enabled already */ + if ((num_vfs > 0) && (num_vfs <= total)) { + if (pdev->sriov->nr_virtfn == 0) { + num_vfs_enabled = + pdev->driver->sriov_configure(pdev, num_vfs); + if ((num_vfs_enabled >= 0) && + (num_vfs_enabled != num_vfs)) { + dev_warn(&pdev->dev, + "Only %d VFs enabled\n", + num_vfs_enabled); + return count; + } else if (num_vfs_enabled < 0) + /* error code from driver callback */ + return num_vfs_enabled; + } else if (num_vfs == pdev->sriov->nr_virtfn) { + dev_warn(&pdev->dev, + "%d VFs already enabled; no enable action taken\n", + num_vfs); + return count; + } else { + dev_warn(&pdev->dev, + "%d VFs already enabled. Disable before enabling %d VFs\n", + pdev->sriov->nr_virtfn, num_vfs); + return -EINVAL; + } + } + + /* disable vfs */ + if (num_vfs == 0) { + if (pdev->sriov->nr_virtfn != 0) { + ret = pdev->driver->sriov_configure(pdev, 0); + return ret ? ret : count; + } else { + dev_warn(&pdev->dev, + "All VFs disabled; no disable action taken\n"); + return count; + } + } + + dev_err(&pdev->dev, + "Invalid value for number of VFs to enable: %d\n", num_vfs); + + return -EINVAL; +} + +static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs); +static struct device_attribute sriov_numvfs_attr = + __ATTR(sriov_numvfs, (S_IRUGO|S_IWUSR|S_IWGRP), + sriov_numvfs_show, sriov_numvfs_store); +#endif /* CONFIG_PCI_IOV */ + struct device_attribute pci_dev_attrs[] = { __ATTR_RO(resource), __ATTR_RO(vendor), @@ -1421,6 +1521,30 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj, return a->mode; } +#ifdef CONFIG_PCI_IOV +static struct attribute *sriov_dev_attrs[] = { + &sriov_totalvfs_attr.attr, + &sriov_numvfs_attr.attr, + NULL, +}; + +static umode_t sriov_attrs_are_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + + if (!dev_is_pf(dev)) + return 0; + + return a->mode; +} + +static struct attribute_group sriov_dev_attr_group = { + .attrs = sriov_dev_attrs, + .is_visible = sriov_attrs_are_visible, +}; +#endif /* CONFIG_PCI_IOV */ + static struct attribute_group pci_dev_attr_group = { .attrs = pci_dev_dev_attrs, .is_visible = pci_dev_attrs_are_visible, @@ -1428,6 +1552,9 @@ static struct attribute_group pci_dev_attr_group = { static const struct attribute_group *pci_dev_attr_groups[] = { &pci_dev_attr_group, +#ifdef CONFIG_PCI_IOV + &sriov_dev_attr_group, +#endif NULL, }; -- cgit v1.2.1 From bff73156d3ad661655e6d9ef04c2284cf3abb0f1 Mon Sep 17 00:00:00 2001 From: Donald Dutile Date: Mon, 5 Nov 2012 15:20:37 -0500 Subject: PCI: Provide method to reduce the number of total VFs supported Some implementations of SRIOV provide a capability structure value of TotalVFs that is greater than what the software can support. Provide a method to reduce the capability structure reported value to the value the driver can support. This ensures sysfs reports the current capability of the system, hardware and software. Example for its use: igb & ixgbe -- report 8 & 64 as TotalVFs, but drivers only support 7 & 63 maximum. Signed-off-by: Donald Dutile Signed-off-by: Bjorn Helgaas --- drivers/pci/iov.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci-sysfs.c | 4 ++-- drivers/pci/pci.h | 1 + 3 files changed, 50 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index aeccc911abb8..f6781e42d00d 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -735,3 +735,50 @@ int pci_num_vf(struct pci_dev *dev) return dev->sriov->nr_virtfn; } EXPORT_SYMBOL_GPL(pci_num_vf); + +/** + * pci_sriov_set_totalvfs -- reduce the TotalVFs available + * @dev: the PCI PF device + * numvfs: number that should be used for TotalVFs supported + * + * Should be called from PF driver's probe routine with + * device's mutex held. + * + * Returns 0 if PF is an SRIOV-capable device and + * value of numvfs valid. If not a PF with VFS, return -EINVAL; + * if VFs already enabled, return -EBUSY. + */ +int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) +{ + if (!dev || !dev->is_physfn || (numvfs > dev->sriov->total)) + return -EINVAL; + + /* Shouldn't change if VFs already enabled */ + if (dev->sriov->ctrl & PCI_SRIOV_CTRL_VFE) + return -EBUSY; + else + dev->sriov->drvttl = numvfs; + + return 0; +} +EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs); + +/** + * pci_sriov_get_totalvfs -- get total VFs supported on this devic3 + * @dev: the PCI PF device + * + * For a PCIe device with SRIOV support, return the PCIe + * SRIOV capability value of TotalVFs or the value of drvttl + * if the driver reduced it. Otherwise, -EINVAL. + */ +int pci_sriov_get_totalvfs(struct pci_dev *dev) +{ + if (!dev || !dev->is_physfn) + return -EINVAL; + + if (dev->sriov->drvttl) + return dev->sriov->drvttl; + else + return dev->sriov->total; +} +EXPORT_SYMBOL_GPL(pci_sriov_get_totalvfs); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 74508c63bd47..99b5f83d2468 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -411,7 +411,7 @@ static ssize_t sriov_totalvfs_show(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf(buf, "%u\n", pdev->sriov->total); + return sprintf(buf, "%u\n", pci_sriov_get_totalvfs(pdev)); } @@ -452,7 +452,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, } /* if enabling vf's ... */ - total = pdev->sriov->total; + total = pci_sriov_get_totalvfs(pdev); /* Requested VFs to enable < totalvfs and none enabled already */ if ((num_vfs > 0) && (num_vfs <= total)) { if (pdev->sriov->nr_virtfn == 0) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 6f6cd145bb7e..553bbba76eec 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -240,6 +240,7 @@ struct pci_sriov { u16 stride; /* following VF stride */ u32 pgsz; /* page size for BAR alignment */ u8 link; /* Function Dependency Link */ + u16 drvttl; /* max num VFs driver supports */ struct pci_dev *dev; /* lowest numbered PF */ struct pci_dev *self; /* this PF */ struct mutex lock; /* lock for VF bus */ -- cgit v1.2.1 From 6b136724691a6f247ada0c6a5f02370ed46de9f4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 9 Nov 2012 20:27:53 -0700 Subject: PCI: Use spec names for SR-IOV capability fields Use the same names (almost) as the spec for TotalVFs, InitialVFs, NumVFs. Signed-off-by: Bjorn Helgaas --- drivers/pci/iov.c | 48 ++++++++++++++++++++++++------------------------ drivers/pci/pci-sysfs.c | 10 +++++----- drivers/pci/pci.h | 8 ++++---- 3 files changed, 33 insertions(+), 33 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index f6781e42d00d..a32bd9ad0931 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -106,7 +106,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) virtfn->resource[i].name = pci_name(virtfn); virtfn->resource[i].flags = res->flags; size = resource_size(res); - do_div(size, iov->total); + do_div(size, iov->total_VFs); virtfn->resource[i].start = res->start + size * id; virtfn->resource[i].end = virtfn->resource[i].start + size - 1; rc = request_resource(res, &virtfn->resource[i]); @@ -194,7 +194,7 @@ static int sriov_migration(struct pci_dev *dev) u16 status; struct pci_sriov *iov = dev->sriov; - if (!iov->nr_virtfn) + if (!iov->num_VFs) return 0; if (!(iov->cap & PCI_SRIOV_CAP_VFM)) @@ -216,7 +216,7 @@ static void sriov_migration_task(struct work_struct *work) u16 status; struct pci_sriov *iov = container_of(work, struct pci_sriov, mtask); - for (i = iov->initial; i < iov->nr_virtfn; i++) { + for (i = iov->initial_VFs; i < iov->num_VFs; i++) { state = readb(iov->mstate + i); if (state == PCI_SRIOV_VFM_MI) { writeb(PCI_SRIOV_VFM_AV, iov->mstate + i); @@ -244,7 +244,7 @@ static int sriov_enable_migration(struct pci_dev *dev, int nr_virtfn) resource_size_t pa; struct pci_sriov *iov = dev->sriov; - if (nr_virtfn <= iov->initial) + if (nr_virtfn <= iov->initial_VFs) return 0; pci_read_config_dword(dev, iov->pos + PCI_SRIOV_VFM, &table); @@ -294,15 +294,15 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) if (!nr_virtfn) return 0; - if (iov->nr_virtfn) + if (iov->num_VFs) return -EINVAL; pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial); - if (initial > iov->total || - (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total))) + if (initial > iov->total_VFs || + (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total_VFs))) return -EIO; - if (nr_virtfn < 0 || nr_virtfn > iov->total || + if (nr_virtfn < 0 || nr_virtfn > iov->total_VFs || (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial))) return -EINVAL; @@ -359,7 +359,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) msleep(100); pci_cfg_access_unlock(dev); - iov->initial = initial; + iov->initial_VFs = initial; if (nr_virtfn < initial) initial = nr_virtfn; @@ -376,7 +376,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) } kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE); - iov->nr_virtfn = nr_virtfn; + iov->num_VFs = nr_virtfn; return 0; @@ -401,13 +401,13 @@ static void sriov_disable(struct pci_dev *dev) int i; struct pci_sriov *iov = dev->sriov; - if (!iov->nr_virtfn) + if (!iov->num_VFs) return; if (iov->cap & PCI_SRIOV_CAP_VFM) sriov_disable_migration(dev); - for (i = 0; i < iov->nr_virtfn; i++) + for (i = 0; i < iov->num_VFs; i++) virtfn_remove(dev, i, 0); iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); @@ -419,7 +419,7 @@ static void sriov_disable(struct pci_dev *dev) if (iov->link != dev->devfn) sysfs_remove_link(&dev->dev.kobj, "dep_link"); - iov->nr_virtfn = 0; + iov->num_VFs = 0; } static int sriov_init(struct pci_dev *dev, int pos) @@ -496,7 +496,7 @@ found: iov->pos = pos; iov->nres = nres; iov->ctrl = ctrl; - iov->total = total; + iov->total_VFs = total; iov->offset = offset; iov->stride = stride; iov->pgsz = pgsz; @@ -529,7 +529,7 @@ failed: static void sriov_release(struct pci_dev *dev) { - BUG_ON(dev->sriov->nr_virtfn); + BUG_ON(dev->sriov->num_VFs); if (dev != dev->sriov->dev) pci_dev_put(dev->sriov->dev); @@ -554,7 +554,7 @@ static void sriov_restore_state(struct pci_dev *dev) pci_update_resource(dev, i); pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz); - pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, iov->nr_virtfn); + pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, iov->num_VFs); pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); if (iov->ctrl & PCI_SRIOV_CTRL_VFE) msleep(100); @@ -661,7 +661,7 @@ int pci_iov_bus_range(struct pci_bus *bus) list_for_each_entry(dev, &bus->devices, bus_list) { if (!dev->is_physfn) continue; - busnr = virtfn_bus(dev, dev->sriov->total - 1); + busnr = virtfn_bus(dev, dev->sriov->total_VFs - 1); if (busnr > max) max = busnr; } @@ -732,7 +732,7 @@ int pci_num_vf(struct pci_dev *dev) if (!dev || !dev->is_physfn) return 0; else - return dev->sriov->nr_virtfn; + return dev->sriov->num_VFs; } EXPORT_SYMBOL_GPL(pci_num_vf); @@ -750,14 +750,14 @@ EXPORT_SYMBOL_GPL(pci_num_vf); */ int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) { - if (!dev || !dev->is_physfn || (numvfs > dev->sriov->total)) + if (!dev || !dev->is_physfn || (numvfs > dev->sriov->total_VFs)) return -EINVAL; /* Shouldn't change if VFs already enabled */ if (dev->sriov->ctrl & PCI_SRIOV_CTRL_VFE) return -EBUSY; else - dev->sriov->drvttl = numvfs; + dev->sriov->driver_max_VFs = numvfs; return 0; } @@ -768,7 +768,7 @@ EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs); * @dev: the PCI PF device * * For a PCIe device with SRIOV support, return the PCIe - * SRIOV capability value of TotalVFs or the value of drvttl + * SRIOV capability value of TotalVFs or the value of driver_max_VFs * if the driver reduced it. Otherwise, -EINVAL. */ int pci_sriov_get_totalvfs(struct pci_dev *dev) @@ -776,9 +776,9 @@ int pci_sriov_get_totalvfs(struct pci_dev *dev) if (!dev || !dev->is_physfn) return -EINVAL; - if (dev->sriov->drvttl) - return dev->sriov->drvttl; + if (dev->sriov->driver_max_VFs) + return dev->sriov->driver_max_VFs; else - return dev->sriov->total; + return dev->sriov->total_VFs; } EXPORT_SYMBOL_GPL(pci_sriov_get_totalvfs); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 99b5f83d2468..2f21991b8bcd 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -421,7 +421,7 @@ static ssize_t sriov_numvfs_show(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf(buf, "%u\n", pdev->sriov->nr_virtfn); + return sprintf(buf, "%u\n", pdev->sriov->num_VFs); } /* @@ -455,7 +455,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, total = pci_sriov_get_totalvfs(pdev); /* Requested VFs to enable < totalvfs and none enabled already */ if ((num_vfs > 0) && (num_vfs <= total)) { - if (pdev->sriov->nr_virtfn == 0) { + if (pdev->sriov->num_VFs == 0) { num_vfs_enabled = pdev->driver->sriov_configure(pdev, num_vfs); if ((num_vfs_enabled >= 0) && @@ -467,7 +467,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, } else if (num_vfs_enabled < 0) /* error code from driver callback */ return num_vfs_enabled; - } else if (num_vfs == pdev->sriov->nr_virtfn) { + } else if (num_vfs == pdev->sriov->num_VFs) { dev_warn(&pdev->dev, "%d VFs already enabled; no enable action taken\n", num_vfs); @@ -475,14 +475,14 @@ static ssize_t sriov_numvfs_store(struct device *dev, } else { dev_warn(&pdev->dev, "%d VFs already enabled. Disable before enabling %d VFs\n", - pdev->sriov->nr_virtfn, num_vfs); + pdev->sriov->num_VFs, num_vfs); return -EINVAL; } } /* disable vfs */ if (num_vfs == 0) { - if (pdev->sriov->nr_virtfn != 0) { + if (pdev->sriov->num_VFs != 0) { ret = pdev->driver->sriov_configure(pdev, 0); return ret ? ret : count; } else { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 553bbba76eec..3c9443ee00e6 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -233,14 +233,14 @@ struct pci_sriov { int nres; /* number of resources */ u32 cap; /* SR-IOV Capabilities */ u16 ctrl; /* SR-IOV Control */ - u16 total; /* total VFs associated with the PF */ - u16 initial; /* initial VFs associated with the PF */ - u16 nr_virtfn; /* number of VFs available */ + u16 total_VFs; /* total VFs associated with the PF */ + u16 initial_VFs; /* initial VFs associated with the PF */ + u16 num_VFs; /* number of VFs available */ u16 offset; /* first VF Routing ID offset */ u16 stride; /* following VF stride */ u32 pgsz; /* page size for BAR alignment */ u8 link; /* Function Dependency Link */ - u16 drvttl; /* max num VFs driver supports */ + u16 driver_max_VFs; /* max num VFs driver supports */ struct pci_dev *dev; /* lowest numbered PF */ struct pci_dev *self; /* this PF */ struct mutex lock; /* lock for VF bus */ -- cgit v1.2.1 From 1452cd76a97bf7b93a015586dcabc73fd935e692 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 9 Nov 2012 20:35:01 -0700 Subject: PCI: Remove useless "!dev" tests No need to check "!dev" when the caller should always supply a valid pointer. If the caller *doesn't* supply a valid pointer, it probably won't check for a failure return either. This way we'll oops and get a backtrace. Signed-off-by: Bjorn Helgaas --- drivers/pci/iov.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index a32bd9ad0931..bafd2bbcaf65 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -729,10 +729,10 @@ EXPORT_SYMBOL_GPL(pci_sriov_migration); */ int pci_num_vf(struct pci_dev *dev) { - if (!dev || !dev->is_physfn) + if (!dev->is_physfn) return 0; - else - return dev->sriov->num_VFs; + + return dev->sriov->num_VFs; } EXPORT_SYMBOL_GPL(pci_num_vf); @@ -750,7 +750,7 @@ EXPORT_SYMBOL_GPL(pci_num_vf); */ int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) { - if (!dev || !dev->is_physfn || (numvfs > dev->sriov->total_VFs)) + if (!dev->is_physfn || (numvfs > dev->sriov->total_VFs)) return -EINVAL; /* Shouldn't change if VFs already enabled */ @@ -773,12 +773,12 @@ EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs); */ int pci_sriov_get_totalvfs(struct pci_dev *dev) { - if (!dev || !dev->is_physfn) + if (!dev->is_physfn) return -EINVAL; if (dev->sriov->driver_max_VFs) return dev->sriov->driver_max_VFs; - else - return dev->sriov->total_VFs; + + return dev->sriov->total_VFs; } EXPORT_SYMBOL_GPL(pci_sriov_get_totalvfs); -- cgit v1.2.1 From eba48cd0f05ff7a2f82291feae169c14b61b29af Mon Sep 17 00:00:00 2001 From: Andrew Cooks Date: Tue, 13 Nov 2012 12:39:07 +0800 Subject: PCI: Add GPL license for drivers/pci/ioapic module Config PCI_IOAPIC turned into a tristate in commit b95a7bd70046, but no module license is specified. This adds the missing module license. Signed-off-by: Andrew Cooks Signed-off-by: Bjorn Helgaas Acked-by: Jan Beulich --- drivers/pci/ioapic.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c index 205af8dc83c2..22436f74eb50 100644 --- a/drivers/pci/ioapic.c +++ b/drivers/pci/ioapic.c @@ -125,3 +125,5 @@ static void __exit ioapic_exit(void) module_init(ioapic_init); module_exit(ioapic_exit); + +MODULE_LICENSE("GPL"); -- cgit v1.2.1 From 918b4053184c0ca22236e70e299c5343eea35304 Mon Sep 17 00:00:00 2001 From: Vijay Mohan Pandarathil Date: Sat, 17 Nov 2012 11:47:18 +0000 Subject: PCI/AER: Report success only when every device has AER-aware driver When an error is detected on a PCIe device which does not have an AER-aware driver, prevent AER infrastructure from reporting successful error recovery. This is because the report_error_detected() function that gets called in the first phase of recovery process allows forward progress even when the driver for the device does not have AER capabilities. It seems that all callbacks (in pci_error_handlers structure) registered by drivers that gets called during error recovery are not mandatory. So the intention of the infrastructure design seems to be to allow forward progress even when a specific callback has not been registered by a driver. However, if error handler structure itself has not been registered, it doesn't make sense to allow forward progress. As a result of the current design, in the case of a single device having an AER-unaware driver or in the case of any function in a multi-function card having an AER-unaware driver, a successful recovery is reported. Typical scenario this happens is when a PCI device is detached from a KVM host and the pci-stub driver on the host claims the device. The pci-stub driver does not have error handling capabilities but the AER infrastructure still reports that the device recovered successfully. The changes proposed here leaves the device(s)in an unrecovered state if the driver for the device or for any device in the subtree does not have error handler structure registered. This reflects the true state of the device and prevents any partial recovery (or no recovery at all) reported as successful. [bhelgaas: changelog] Signed-off-by: Vijay Mohan Pandarathil Signed-off-by: Bjorn Helgaas Reviewed-by: Linas Vepstas Reviewed-by: Myron Stowe --- drivers/pci/pcie/aer/aerdrv.h | 5 ++++- drivers/pci/pcie/aer/aerdrv_core.c | 21 ++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index 94a7598eb262..22f840f4dda1 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -87,6 +87,9 @@ struct aer_broadcast_data { static inline pci_ers_result_t merge_result(enum pci_ers_result orig, enum pci_ers_result new) { + if (new == PCI_ERS_RESULT_NO_AER_DRIVER) + return PCI_ERS_RESULT_NO_AER_DRIVER; + if (new == PCI_ERS_RESULT_NONE) return orig; @@ -97,7 +100,7 @@ static inline pci_ers_result_t merge_result(enum pci_ers_result orig, break; case PCI_ERS_RESULT_DISCONNECT: if (new == PCI_ERS_RESULT_NEED_RESET) - orig = new; + orig = PCI_ERS_RESULT_NEED_RESET; break; default: break; diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 06bad96af415..eb2f19a9c3cd 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -231,11 +231,26 @@ static int report_error_detected(struct pci_dev *dev, void *data) dev->driver ? "no AER-aware driver" : "no driver"); } - return 0; + + /* + * If there's any device in the subtree that does not + * have an error_detected callback, returning + * PCI_ERS_RESULT_NO_AER_DRIVER prevents calling of + * the subsequent mmio_enabled/slot_reset/resume + * callbacks of "any" device in the subtree. All the + * devices in the subtree are left in the error state + * without recovery. + */ + + if (!(dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) + vote = PCI_ERS_RESULT_NO_AER_DRIVER; + else + vote = PCI_ERS_RESULT_NONE; + } else { + err_handler = dev->driver->err_handler; + vote = err_handler->error_detected(dev, result_data->state); } - err_handler = dev->driver->err_handler; - vote = err_handler->error_detected(dev, result_data->state); result_data->result = merge_result(result_data->result, vote); return 0; } -- cgit v1.2.1 From d5af64de2d1cc87d77ac7c0e90d89630a37a4f09 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 18 Oct 2012 11:03:36 +0100 Subject: xen-pcifront: Handle backend CLOSED without CLOSING Backend drivers shouldn't transition to CLOSED unless the frontend is CLOSED. If a backend does transition to CLOSED too soon then the frontend may not see the CLOSING state and will not properly shutdown. So, treat an unexpected backend CLOSED state the same as CLOSING. Signed-off-by: David Vrabel Signed-off-by: Bjorn Helgaas Acked-by: Konrad Rzeszutek Wilk --- drivers/pci/xen-pcifront.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 0aab85a51559..a0c73120b262 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -1068,13 +1068,16 @@ static void __init_refok pcifront_backend_changed(struct xenbus_device *xdev, case XenbusStateInitialising: case XenbusStateInitWait: case XenbusStateInitialised: - case XenbusStateClosed: break; case XenbusStateConnected: pcifront_try_connect(pdev); break; + case XenbusStateClosed: + if (xdev->state == XenbusStateClosed) + break; + /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: dev_warn(&xdev->dev, "backend going away!\n"); pcifront_try_disconnect(pdev); -- cgit v1.2.1 From 967577b062417b4e4b8e27b711220f4124f5153a Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Tue, 20 Nov 2012 16:08:22 +0800 Subject: PCI/PM: Keep runtime PM enabled for unbound PCI devices For unbound PCI devices, what we need is: - Always in D0 state, because some devices do not work again after being put into D3 by the PCI bus. - In SUSPENDED state if allowed, so that the parent devices can still be put into low power state. To satisfy these requirements, the runtime PM for the unbound PCI devices are disabled and set to SUSPENDED state. One issue of this solution is that the PCI devices will be put into SUSPENDED state even if the SUSPENDED state is forbidden via the sysfs interface (.../power/control) of the device. This is not an issue for most devices, because most PCI devices are not used at all if unbound. But there are exceptions. For example, unbound VGA card can be used for display, but suspending its parents makes it stop working. To fix the issue, we keep the runtime PM enabled when the PCI devices are unbound. But the runtime PM callbacks will do nothing if the PCI devices are unbound. This way, we can put the PCI devices into SUSPENDED state without putting the PCI devices into D3 state. Reference: https://bugzilla.kernel.org/show_bug.cgi?id=48201 Signed-off-by: Huang Ying Signed-off-by: Bjorn Helgaas Acked-by: Alan Stern Acked-by: Rafael J. Wysocki CC: stable@vger.kernel.org # v3.6+ --- drivers/pci/pci-driver.c | 67 +++++++++++++++++++++++++++++------------------- drivers/pci/pci.c | 2 ++ 2 files changed, 42 insertions(+), 27 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 6c94fc9489e7..6c66c5b8e152 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -256,31 +256,26 @@ struct drv_dev_and_id { static long local_pci_probe(void *_ddi) { struct drv_dev_and_id *ddi = _ddi; - struct device *dev = &ddi->dev->dev; - struct device *parent = dev->parent; + struct pci_dev *pci_dev = ddi->dev; + struct pci_driver *pci_drv = ddi->drv; + struct device *dev = &pci_dev->dev; int rc; - /* The parent bridge must be in active state when probing */ - if (parent) - pm_runtime_get_sync(parent); - /* Unbound PCI devices are always set to disabled and suspended. - * During probe, the device is set to enabled and active and the - * usage count is incremented. If the driver supports runtime PM, - * it should call pm_runtime_put_noidle() in its probe routine and - * pm_runtime_get_noresume() in its remove routine. + /* + * Unbound PCI devices are always put in D0, regardless of + * runtime PM status. During probe, the device is set to + * active and the usage count is incremented. If the driver + * supports runtime PM, it should call pm_runtime_put_noidle() + * in its probe routine and pm_runtime_get_noresume() in its + * remove routine. */ - pm_runtime_get_noresume(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - - rc = ddi->drv->probe(ddi->dev, ddi->id); + pm_runtime_get_sync(dev); + pci_dev->driver = pci_drv; + rc = pci_drv->probe(pci_dev, ddi->id); if (rc) { - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); - pm_runtime_put_noidle(dev); + pci_dev->driver = NULL; + pm_runtime_put_sync(dev); } - if (parent) - pm_runtime_put(parent); return rc; } @@ -330,10 +325,8 @@ __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) { - pci_dev->driver = drv; + if (error >= 0) error = 0; - } } return error; } @@ -369,9 +362,7 @@ static int pci_device_remove(struct device * dev) } /* Undo the runtime PM settings in local_pci_probe() */ - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); - pm_runtime_put_noidle(dev); + pm_runtime_put_sync(dev); /* * If the device is still on, set the power state as "unknown", @@ -994,6 +985,13 @@ static int pci_pm_runtime_suspend(struct device *dev) pci_power_t prev = pci_dev->current_state; int error; + /* + * If pci_dev->driver is not set (unbound), the device should + * always remain in D0 regardless of the runtime PM status + */ + if (!pci_dev->driver) + return 0; + if (!pm || !pm->runtime_suspend) return -ENOSYS; @@ -1029,6 +1027,13 @@ static int pci_pm_runtime_resume(struct device *dev) struct pci_dev *pci_dev = to_pci_dev(dev); const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + /* + * If pci_dev->driver is not set (unbound), the device should + * always remain in D0 regardless of the runtime PM status + */ + if (!pci_dev->driver) + return 0; + if (!pm || !pm->runtime_resume) return -ENOSYS; @@ -1046,8 +1051,16 @@ static int pci_pm_runtime_resume(struct device *dev) static int pci_pm_runtime_idle(struct device *dev) { + struct pci_dev *pci_dev = to_pci_dev(dev); const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + /* + * If pci_dev->driver is not set (unbound), the device should + * always remain in D0 regardless of the runtime PM status + */ + if (!pci_dev->driver) + goto out; + if (!pm) return -ENOSYS; @@ -1057,8 +1070,8 @@ static int pci_pm_runtime_idle(struct device *dev) return ret; } +out: pm_runtime_suspend(dev); - return 0; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index aabf64798bda..8e06adb9898f 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1900,6 +1900,8 @@ void pci_pm_init(struct pci_dev *dev) u16 pmc; pm_runtime_forbid(&dev->dev); + pm_runtime_set_active(&dev->dev); + pm_runtime_enable(&dev->dev); device_enable_async_suspend(&dev->dev); dev->wakeup_prepared = false; -- cgit v1.2.1 From 7793eeabc89fd342b96fdadce5a50c46ab77f3f9 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 5 Dec 2012 13:51:17 -0700 Subject: PCI: Add and use standard PCI-X Capability register names Add and use #defines for PCI-X Capability registers and fields. Note that the PCI-X Capability has a different layout for type 0 (endpoint) and type 1 (bridge) devices. Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ec909afa90b6..81d06676ce34 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -579,14 +579,16 @@ static void pci_set_bus_speed(struct pci_bus *bus) if (pos) { u16 status; enum pci_bus_speed max; - pci_read_config_word(bridge, pos + 2, &status); - if (status & 0x8000) { + pci_read_config_word(bridge, pos + PCI_X_BRIDGE_SSTATUS, + &status); + + if (status & PCI_X_SSTATUS_533MHZ) { max = PCI_SPEED_133MHz_PCIX_533; - } else if (status & 0x4000) { + } else if (status & PCI_X_SSTATUS_266MHZ) { max = PCI_SPEED_133MHz_PCIX_266; - } else if (status & 0x0002) { - if (((status >> 12) & 0x3) == 2) { + } else if (status & PCI_X_SSTATUS_133MHZ) { + if ((status & PCI_X_SSTATUS_VERS) == PCI_X_SSTATUS_V2) { max = PCI_SPEED_133MHz_PCIX_ECC; } else { max = PCI_SPEED_133MHz_PCIX; @@ -596,7 +598,8 @@ static void pci_set_bus_speed(struct pci_bus *bus) } bus->max_bus_speed = max; - bus->cur_bus_speed = pcix_bus_speed[(status >> 6) & 0xf]; + bus->cur_bus_speed = pcix_bus_speed[ + (status & PCI_X_SSTATUS_FREQ) >> 6]; return; } -- cgit v1.2.1 From eca0d4676d8e29c209ddce0c0c1755472ffc70a6 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 5 Dec 2012 14:33:27 -0700 Subject: PCI: Add pcibios_add_device Platforms may want to provide architecture-specific functionality during PCI enumeration. Add a pcibios_add_device() call that architectures can override to do so. Signed-off-by: Matthew Garrett Signed-off-by: Bjorn Helgaas Tested-by: Seth Forshee --- drivers/pci/bus.c | 5 +++++ drivers/pci/pci.c | 13 +++++++++++++ 2 files changed, 18 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 6241fd05bd41..4f22fa16a3ba 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -170,6 +170,11 @@ int pci_bus_add_device(struct pci_dev *dev) int retval; pci_fixup_device(pci_fixup_final, dev); + + retval = pcibios_add_device(dev); + if (retval) + return retval; + retval = device_add(&dev->dev); if (retval) return retval; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 54858838f098..fa0ddd51a216 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1333,6 +1333,19 @@ void pcim_pin_device(struct pci_dev *pdev) dr->pinned = 1; } +/* + * pcibios_add_device - provide arch specific hooks when adding device dev + * @dev: the PCI device being added + * + * Permits the platform to provide architecture specific functionality when + * devices are added. This is the default implementation. Architecture + * implementations can override this. + */ +int __weak pcibios_add_device (struct pci_dev *dev) +{ + return 0; +} + /** * pcibios_disable_device - disable arch specific PCI resources for device dev * @dev: the PCI device to disable -- cgit v1.2.1 From 84c1b80e32638f881c17390dfe88143e5cd3f583 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 5 Dec 2012 14:33:27 -0700 Subject: PCI: Add support for non-BAR ROMs Platforms may provide their own mechanisms for obtaining ROMs. Add support for using data provided by the platform in that case. Signed-off-by: Matthew Garrett Signed-off-by: Bjorn Helgaas Tested-by: Seth Forshee --- drivers/pci/rom.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index 0b3037ab8b93..3a3828fbc879 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -117,12 +117,18 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) loff_t start; void __iomem *rom; + /* + * Some devices may provide ROMs via a source other than the BAR + */ + if (pdev->rom && pdev->romlen) { + *size = pdev->romlen; + return phys_to_virt((phys_addr_t)pdev->rom); /* * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy * memory map if the VGA enable bit of the Bridge Control register is * set for embedded VGA. */ - if (res->flags & IORESOURCE_ROM_SHADOW) { + } else if (res->flags & IORESOURCE_ROM_SHADOW) { /* primary video rom always starts here */ start = (loff_t)0xC0000; *size = 0x20000; /* cover C000:0 through E000:0 */ @@ -181,7 +187,8 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) return; - iounmap(rom); + if (!pdev->rom || !pdev->romlen) + iounmap(rom); /* Disable again before continuing, leave enabled if pci=rom */ if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW))) -- cgit v1.2.1 From 231afea189c6363f2921042576da74e1fb0f2fc3 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 5 Dec 2012 13:51:18 -0700 Subject: PCI: Use standard PCIe Capability Link register field names Use the standard #defines for PCIe Link Status and Capability registers rather than bare numbers. Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 81d06676ce34..7ec6973378fe 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -521,7 +521,7 @@ static unsigned char pcie_link_speed[] = { void pcie_update_link_speed(struct pci_bus *bus, u16 linksta) { - bus->cur_bus_speed = pcie_link_speed[linksta & 0xf]; + bus->cur_bus_speed = pcie_link_speed[linksta & PCI_EXP_LNKSTA_CLS]; } EXPORT_SYMBOL_GPL(pcie_update_link_speed); @@ -610,7 +610,7 @@ static void pci_set_bus_speed(struct pci_bus *bus) u16 linksta; pcie_capability_read_dword(bridge, PCI_EXP_LNKCAP, &linkcap); - bus->max_bus_speed = pcie_link_speed[linkcap & 0xf]; + bus->max_bus_speed = pcie_link_speed[linkcap & PCI_EXP_LNKCAP_SLS]; pcie_capability_read_word(bridge, PCI_EXP_LNKSTA, &linksta); pcie_update_link_speed(bus, linksta); -- cgit v1.2.1 From 33e8b34fdd5640f3aa1597710352349cbc823374 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 5 Dec 2012 13:51:18 -0700 Subject: PCI/portdrv: Use PCI Express Capability accessors Use PCI Express Capability access functions to simplify portdrv. Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/portdrv_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index d03a7a39b2d8..70d3555903ae 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -120,8 +120,7 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) * the value in this field indicates which MSI-X Table entry is * used to generate the interrupt message." */ - pos = pci_pcie_cap(dev); - pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16); + pcie_capability_read_word(dev, PCI_EXP_FLAGS, ®16); entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9; if (entry >= nr_entries) goto Error; -- cgit v1.2.1 From 7508320678b7819ac6aeb89580b8622a424ce586 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 5 Dec 2012 13:51:19 -0700 Subject: PCI: Add standard PCIe Capability Link ASPM field names Add standard #defines for ASPM fields in PCI Express Link Capability and Link Control registers. Previously we used PCIE_LINK_STATE_L0S and PCIE_LINK_STATE_L1 directly, but these are defined for the Linux ASPM interfaces, e.g., pci_disable_link_state(), and only coincidentally match the actual register bits. PCIE_LINK_STATE_CLKPM, also part of that interface, does not match the register bit. Signed-off-by: Bjorn Helgaas Reviewed-by: Kenji Kaneshige Acked-by: Kenji Kaneshige --- drivers/pci/pcie/aspm.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 213753b283a6..c2faf9d0ffde 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -427,7 +427,8 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val) { - pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL, 0x3, val); + pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_ASPMC, val); } static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state) @@ -442,12 +443,12 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state) return; /* Convert ASPM state to upstream/downstream ASPM register state */ if (state & ASPM_STATE_L0S_UP) - dwstream |= PCIE_LINK_STATE_L0S; + dwstream |= PCI_EXP_LNKCTL_ASPM_L0S; if (state & ASPM_STATE_L0S_DW) - upstream |= PCIE_LINK_STATE_L0S; + upstream |= PCI_EXP_LNKCTL_ASPM_L0S; if (state & ASPM_STATE_L1) { - upstream |= PCIE_LINK_STATE_L1; - dwstream |= PCIE_LINK_STATE_L1; + upstream |= PCI_EXP_LNKCTL_ASPM_L1; + dwstream |= PCI_EXP_LNKCTL_ASPM_L1; } /* * Spec 2.0 suggests all functions should be configured the -- cgit v1.2.1 From dbd3fc3345390a989a033427aa915a0dfb62149f Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 10 Dec 2012 11:24:42 -0700 Subject: PCI: Use phys_addr_t for physical ROM address Use phys_addr_t rather than "void *" for physical memory address. This removes casts and fixes a "cast from pointer to integer of different size" warning on ppc44x_defconfig. Signed-off-by: Bjorn Helgaas --- drivers/pci/rom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index 3a3828fbc879..ab886b7ee327 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -122,7 +122,7 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) */ if (pdev->rom && pdev->romlen) { *size = pdev->romlen; - return phys_to_virt((phys_addr_t)pdev->rom); + return phys_to_virt(pdev->rom); /* * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy * memory map if the VGA enable bit of the Bridge Control register is -- cgit v1.2.1