From 3ebe7f9f7e4a4fd1f6461ecd01ff2961317a483a Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Fri, 2 May 2014 10:40:42 -0600 Subject: [PATCH 01/17] PCI: Notify driver before and after device reset Notify a PCI device driver when its device's access is about to be disabled for an impending reset attempt, then after the attempt completes and device access is restored. The notification is via the pci_error_handlers interface. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 21 +++++++++++++++++++++ include/linux/pci.h | 3 +++ 2 files changed, 24 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7325d43bf030..43d87b26ec5b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3305,8 +3305,27 @@ static void pci_dev_unlock(struct pci_dev *dev) pci_cfg_access_unlock(dev); } +/** + * pci_reset_notify - notify device driver of reset + * @dev: device to be notified of reset + * @prepare: 'true' if device is about to be reset; 'false' if reset attempt + * completed + * + * Must be called prior to device access being disabled and after device + * access is restored. + */ +static void pci_reset_notify(struct pci_dev *dev, bool prepare) +{ + const struct pci_error_handlers *err_handler = + dev->driver ? dev->driver->err_handler : NULL; + if (err_handler && err_handler->reset_notify) + err_handler->reset_notify(dev, prepare); +} + static void pci_dev_save_and_disable(struct pci_dev *dev) { + pci_reset_notify(dev, true); + /* * Wake-up device prior to save. PM registers default to D0 after * reset and a simple register restore doesn't reliably return @@ -3328,6 +3347,7 @@ static void pci_dev_save_and_disable(struct pci_dev *dev) static void pci_dev_restore(struct pci_dev *dev) { pci_restore_state(dev); + pci_reset_notify(dev, false); } static int pci_dev_reset(struct pci_dev *dev, int probe) @@ -3344,6 +3364,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) return rc; } + /** * __pci_reset_function - reset a PCI device function * @dev: PCI device to reset diff --git a/include/linux/pci.h b/include/linux/pci.h index aab57b4abe7f..31c43093e538 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -603,6 +603,9 @@ struct pci_error_handlers { /* PCI slot has been reset */ pci_ers_result_t (*slot_reset)(struct pci_dev *dev); + /* PCI function reset prepare or completed */ + void (*reset_notify)(struct pci_dev *dev, bool prepare); + /* Device driver may resume normal operations */ void (*resume)(struct pci_dev *dev); }; From f0d54a541751af2c6a16d0c081788cc2aef922a5 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Fri, 2 May 2014 10:40:43 -0600 Subject: [PATCH 02/17] NVMe: Implement PCIe reset notification callback Quiesce and shutdown the device prior to reset, then restart the device and resume IO after. Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas --- drivers/block/nvme-core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 7c64fa756cce..a842c71dcc21 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -2775,6 +2775,16 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) return result; } +static void nvme_reset_notify(struct pci_dev *pdev, bool prepare) +{ + struct nvme_dev *dev = pci_get_drvdata(pdev); + + if (prepare) + nvme_dev_shutdown(dev); + else + nvme_dev_resume(dev); +} + static void nvme_shutdown(struct pci_dev *pdev) { struct nvme_dev *dev = pci_get_drvdata(pdev); @@ -2839,6 +2849,7 @@ static const struct pci_error_handlers nvme_err_handler = { .link_reset = nvme_link_reset, .slot_reset = nvme_slot_reset, .resume = nvme_error_resume, + .reset_notify = nvme_reset_notify, }; /* Move to pci_ids.h later */ From 326c1cdae74186bfab3464e8f3378c7fa324be12 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:36 +0800 Subject: [PATCH 03/17] PCI: Rename pci_is_bridge() to pci_has_subordinate() Previously, pci_is_bridge() returned true only when a subordinate bus existed. Rename pci_is_bridge() to pci_has_subordinate() to better indicate what we're checking. No functional change. [bhelgaas: changelog] Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-driver.c | 8 ++++---- drivers/pci/pci.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d911e0c1f359..b7850cb4b907 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -580,14 +580,14 @@ static void pci_pm_default_resume(struct pci_dev *pci_dev) { pci_fixup_device(pci_fixup_resume, pci_dev); - if (!pci_is_bridge(pci_dev)) + if (!pci_has_subordinate(pci_dev)) pci_enable_wake(pci_dev, PCI_D0, false); } static void pci_pm_default_suspend(struct pci_dev *pci_dev) { /* Disable non-bridge devices without PM support */ - if (!pci_is_bridge(pci_dev)) + if (!pci_has_subordinate(pci_dev)) pci_disable_enabled_device(pci_dev); } @@ -717,7 +717,7 @@ static int pci_pm_suspend_noirq(struct device *dev) if (!pci_dev->state_saved) { pci_save_state(pci_dev); - if (!pci_is_bridge(pci_dev)) + if (!pci_has_subordinate(pci_dev)) pci_prepare_to_sleep(pci_dev); } @@ -971,7 +971,7 @@ static int pci_pm_poweroff_noirq(struct device *dev) return error; } - if (!pci_dev->state_saved && !pci_is_bridge(pci_dev)) + if (!pci_dev->state_saved && !pci_has_subordinate(pci_dev)) pci_prepare_to_sleep(pci_dev); /* diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 6bd082299e31..65108fc6f11d 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -77,7 +77,7 @@ static inline void pci_wakeup_event(struct pci_dev *dev) pm_wakeup_event(&dev->dev, 100); } -static inline bool pci_is_bridge(struct pci_dev *pci_dev) +static inline bool pci_has_subordinate(struct pci_dev *pci_dev) { return !!(pci_dev->subordinate); } From 1c86438c9423a26cc9f7f74a8950d9cf9c93bc23 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:37 +0800 Subject: [PATCH 04/17] PCI: Add new pci_is_bridge() interface Add a helper function to check a device's header type for PCI bridge or CardBus bridge. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- include/linux/pci.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/linux/pci.h b/include/linux/pci.h index aab57b4abe7f..f2a5946ea0bf 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -477,6 +477,19 @@ static inline bool pci_is_root_bus(struct pci_bus *pbus) return !(pbus->parent); } +/** + * pci_is_bridge - check if the PCI device is a bridge + * @dev: PCI device + * + * Return true if the PCI device is bridge whether it has subordinate + * or not. + */ +static inline bool pci_is_bridge(struct pci_dev *dev) +{ + return dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS; +} + static inline struct pci_dev *pci_upstream_bridge(struct pci_dev *dev) { dev = pci_physfn(dev); From 6788a51fe3391817c8ded5f43dd4c57f3d212c17 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:38 +0800 Subject: [PATCH 05/17] PCI: Use pci_is_bridge() to simplify code Use pci_is_bridge() to simplify code. No functional change. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Requires: 1c86438c9423 PCI: Add new pci_is_bridge() interface Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 8 +------- drivers/pci/probe.c | 3 +-- drivers/pci/setup-bus.c | 4 +--- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index f49abef88485..ca4927ba8433 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -309,13 +309,7 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev) bool check_children; u64 addr; - /* - * pci_is_bridge() is not suitable here, because pci_dev->subordinate - * is set only after acpi_pci_find_device() has been called for the - * given device. - */ - check_children = pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE - || pci_dev->hdr_type == PCI_HEADER_TYPE_CARDBUS; + check_children = pci_is_bridge(pci_dev); /* Please ref to ACPI spec for the syntax of _ADR */ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ef09f5f2fe6c..f831dd80fa2d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1670,8 +1670,7 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus) for (pass=0; pass < 2; pass++) list_for_each_entry(dev, &bus->devices, bus_list) { - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + if (pci_is_bridge(dev)) max = pci_scan_bridge(bus, dev, max, pass); } diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 138bdd6393be..e399d00ed5fb 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1629,9 +1629,7 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus) down_read(&pci_bus_sem); list_for_each_entry(dev, &bus->devices, bus_list) - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) - if (dev->subordinate) + if (pci_is_bridge(dev) && pci_has_subordinate(dev)) __pci_bus_size_bridges(dev->subordinate, &add_list); up_read(&pci_bus_sem); From 56a41f9949f13dfcf6ceca15723d88d9f5288bb9 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:39 +0800 Subject: [PATCH 06/17] x86/PCI: Use pci_is_bridge() to simplify code Use pci_is_bridge() to simplify code. No functional change. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Requires: 1c86438c9423 PCI: Add new pci_is_bridge() interface Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- arch/x86/pci/fixup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index 94ae9ae9574f..e5f000c02177 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -337,9 +337,7 @@ static void pci_fixup_video(struct pci_dev *pdev) * type BRIDGE, or CARDBUS. Host to PCI controllers use * PCI header type NORMAL. */ - if (bridge - && ((bridge->hdr_type == PCI_HEADER_TYPE_BRIDGE) - || (bridge->hdr_type == PCI_HEADER_TYPE_CARDBUS))) { + if (bridge && (pci_is_bridge(bridge))) { pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &config); if (!(config & PCI_BRIDGE_CTL_VGA)) From 11a3bd095cb1ab62545b3c2105bc11c942063568 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:40 +0800 Subject: [PATCH 07/17] ia64/PCI: Use pci_is_bridge() to simplify code Use pci_is_bridge() to simplify code. No functional change. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Requires: 1c86438c9423 PCI: Add new pci_is_bridge() interface Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- arch/ia64/pci/fixup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/ia64/pci/fixup.c b/arch/ia64/pci/fixup.c index eee069a0b539..1fe9aa5068ea 100644 --- a/arch/ia64/pci/fixup.c +++ b/arch/ia64/pci/fixup.c @@ -49,9 +49,7 @@ static void pci_fixup_video(struct pci_dev *pdev) * type BRIDGE, or CARDBUS. Host to PCI controllers use * PCI header type NORMAL. */ - if (bridge - &&((bridge->hdr_type == PCI_HEADER_TYPE_BRIDGE) - ||(bridge->hdr_type == PCI_HEADER_TYPE_CARDBUS))) { + if (bridge && (pci_is_bridge(bridge))) { pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &config); if (!(config & PCI_BRIDGE_CTL_VGA)) From c888770eb2c9fcc5e735965237759ffbe3a3eee9 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:41 +0800 Subject: [PATCH 08/17] powerpc/PCI: Use pci_is_bridge() to simplify code Use pci_is_bridge() to simplify code. No functional change. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Requires: 1c86438c9423 PCI: Add new pci_is_bridge() interface Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- arch/powerpc/kernel/pci-hotplug.c | 3 +-- arch/powerpc/kernel/pci_of_scan.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/pci-hotplug.c b/arch/powerpc/kernel/pci-hotplug.c index c1e17ae68a08..5b789177aa29 100644 --- a/arch/powerpc/kernel/pci-hotplug.c +++ b/arch/powerpc/kernel/pci-hotplug.c @@ -98,8 +98,7 @@ void pcibios_add_pci_devices(struct pci_bus * bus) max = bus->busn_res.start; for (pass = 0; pass < 2; pass++) { list_for_each_entry(dev, &bus->devices, bus_list) { - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + if (pci_is_bridge(dev)) max = pci_scan_bridge(bus, dev, max, pass); } diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 83c26d829991..059e244484fe 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -362,8 +362,7 @@ static void __of_scan_bus(struct device_node *node, struct pci_bus *bus, /* Now scan child busses */ list_for_each_entry(dev, &bus->devices, bus_list) { - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { + if (pci_is_bridge(dev)) { of_scan_pci_bridge(dev); } } From 2f22e68ab4447a8e3491c09b616a565202eb322f Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:42 +0800 Subject: [PATCH 09/17] sparc/PCI: Use pci_is_bridge() to simplify code Use pci_is_bridge() to simplify code. No functional change. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Requires: 1c86438c9423 PCI: Add new pci_is_bridge() interface Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas Acked-by: David S. Miller --- arch/sparc/kernel/pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 1555bbcae1ee..857ad77df9c0 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -543,8 +543,7 @@ static void pci_of_scan_bus(struct pci_pbm_info *pbm, printk("PCI: dev header type: %x\n", dev->hdr_type); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + if (pci_is_bridge(dev)) of_scan_pci_bridge(pbm, child, dev); } } From f86e1f152e949b24ef336c640009183c01cfd9bf Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:43 +0800 Subject: [PATCH 10/17] PCI: rpaphp: Use pci_is_bridge() to simplify code Use pci_is_bridge() to simplify code. No functional change. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Requires: 1c86438c9423 PCI: Add new pci_is_bridge() interface Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas Acked-by: Benjamin Herrenschmidt --- drivers/pci/hotplug/rpadlpar_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index 4fcdeedda31b..7660232ef460 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -157,8 +157,7 @@ static void dlpar_pci_add_bus(struct device_node *dn) } /* Scan below the new bridge */ - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + if (pci_is_bridge(dev)) of_scan_pci_bridge(dev); /* Map IO space for child bus, which may or may not succeed */ From 087cfa93e0fb5f06c0e976e6f468ffedc83b3223 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:44 +0800 Subject: [PATCH 11/17] PCI: shpchp: Use pci_is_bridge() to simplify code Use pci_is_bridge() to simplify code. No functional change. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Requires: 1c86438c9423 PCI: Add new pci_is_bridge() interface Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/shpchp_pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index 2bf69fe1926c..ea8ad313275c 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -64,8 +64,7 @@ int __ref shpchp_configure_device(struct slot *p_slot) list_for_each_entry(dev, &parent->devices, bus_list) { if (PCI_SLOT(dev->devfn) != p_slot->device) continue; - if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || - (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) + if (pci_is_bridge(dev)) pci_hp_add_bridge(dev); } From 5cbe5d15aefcd57038a90aa8db4787bc84968941 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:45 +0800 Subject: [PATCH 12/17] PCI: cpcihp: Use pci_is_bridge() to simplify code Use pci_is_bridge() to simplify code. No functional change. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Requires: 1c86438c9423 PCI: Add new pci_is_bridge() interface Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/cpci_hotplug_pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 8c1464851768..98433716978a 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -289,8 +289,7 @@ int __ref cpci_configure_slot(struct slot *slot) list_for_each_entry(dev, &parent->devices, bus_list) if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn)) continue; - if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || - (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) + if (pci_is_bridge(dev)) pci_hp_add_bridge(dev); From c7a071f6a9f02c9fd2d0aa81d000c814a7adb914 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:46 +0800 Subject: [PATCH 13/17] PCI: acpiphp: Use pci_is_bridge() to simplify code Use pci_is_bridge() to simplify code. No functional change. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Requires: 1c86438c9423 PCI: Add new pci_is_bridge() interface Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/acpiphp_glue.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index bccc27ee1030..f1f9bd10103d 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -516,8 +516,7 @@ static void __ref enable_slot(struct acpiphp_slot *slot) if (PCI_SLOT(dev->devfn) != slot->device) continue; - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { + if (pci_is_bridge(dev)) { max = pci_scan_bridge(bus, dev, max, pass); if (pass && dev->subordinate) { check_hotplug_bridge(slot, dev); From 930067e235f23c98e444615a03e1f01148cc6d71 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:48 +0800 Subject: [PATCH 14/17] PCI: pciehp: Use pci_is_bridge() to simplify code Use pci_is_bridge() to simplify code. No functional change. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Requires: 1c86438c9423 PCI: Add new pci_is_bridge() interface Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp_pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 1b533060ce65..b6cb1df67097 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -62,8 +62,7 @@ int pciehp_configure_device(struct slot *p_slot) } list_for_each_entry(dev, &parent->devices, bus_list) - if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || - (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) + if (pci_is_bridge(dev)) pci_hp_add_bridge(dev); pci_assign_unassigned_bridge_resources(bridge); From 56604faed1121733de58098db51fb5987f2390ee Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Sun, 4 May 2014 12:23:47 +0800 Subject: [PATCH 15/17] pcmcia: Use pci_is_bridge() to simplify code Use pci_is_bridge() to simplify code. No functional change. Requires: 326c1cdae741 PCI: Rename pci_is_bridge() to pci_has_subordinate() Requires: 1c86438c9423 PCI: Add new pci_is_bridge() interface Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pcmcia/cardbus.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 8bde61952d20..4fe4cc4ae19a 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -78,8 +78,7 @@ int __ref cb_alloc(struct pcmcia_socket *s) max = bus->busn_res.start; for (pass = 0; pass < 2; pass++) list_for_each_entry(dev, &bus->devices, bus_list) - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + if (pci_is_bridge(dev)) max = pci_scan_bridge(bus, dev, max, pass); /* From cab9a128dad0fa0c8400a03d9375c781dda43982 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 18 May 2014 18:02:57 +0200 Subject: [PATCH 16/17] PCI: cpqphp: Fix possible null pointer dereference There is otherwise a risk of a null pointer dereference. Found by cppcheck, a static code analysis program. Signed-off-by: Rickard Strandqvist Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/cpqphp_ctrl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 11845b796799..f593585f2784 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -709,7 +709,8 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz temp = temp->next; } - temp->next = max->next; + if (temp) + temp->next = max->next; } max->next = NULL; From 782a985d7af26db39e86070d28f987cad21313c0 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 20 May 2014 08:53:21 -0600 Subject: [PATCH 17/17] PCI: Introduce new device binding path using pci_dev.driver_override The driver_override field allows us to specify the driver for a device rather than relying on the driver to provide a positive match of the device. This shortcuts the existing process of looking up the vendor and device ID, adding them to the driver new_id, binding the device, then removing the ID, but it also provides a couple advantages. First, the above existing process allows the driver to bind to any device matching the new_id for the window where it's enabled. This is often not desired, such as the case of trying to bind a single device to a meta driver like pci-stub or vfio-pci. Using driver_override we can do this deterministically using: echo pci-stub > /sys/bus/pci/devices/0000:03:00.0/driver_override echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind echo 0000:03:00.0 > /sys/bus/pci/drivers_probe Previously we could not invoke drivers_probe after adding a device to new_id for a driver as we get non-deterministic behavior whether the driver we intend or the standard driver will claim the device. Now it becomes a deterministic process, only the driver matching driver_override will probe the device. To return the device to the standard driver, we simply clear the driver_override and reprobe the device: echo > /sys/bus/pci/devices/0000:03:00.0/driver_override echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind echo 0000:03:00.0 > /sys/bus/pci/drivers_probe Another advantage to this approach is that we can specify a driver override to force a specific binding or prevent any binding. For instance when an IOMMU group is exposed to userspace through VFIO we require that all devices within that group are owned by VFIO. However, devices can be hot-added into an IOMMU group, in which case we want to prevent the device from binding to any driver (override driver = "none") or perhaps have it automatically bind to vfio-pci. With driver_override it's a simple matter for this field to be set internally when the device is first discovered to prevent driver matches. Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas Reviewed-by: Konrad Rzeszutek Wilk Reviewed-by: Alexander Graf Acked-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-pci | 21 +++++++++++++ drivers/pci/pci-driver.c | 25 ++++++++++++++-- drivers/pci/pci-sysfs.c | 40 +++++++++++++++++++++++++ drivers/pci/probe.c | 1 + include/linux/pci.h | 1 + 5 files changed, 85 insertions(+), 3 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index a3c5a6685036..898ddc4440e6 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -250,3 +250,24 @@ Description: valid. For example, writing a 2 to this file when sriov_numvfs is not 0 and not 2 already will return an error. Writing a 10 when the value of sriov_totalvfs is 8 will return an error. + +What: /sys/bus/pci/devices/.../driver_override +Date: April 2014 +Contact: Alex Williamson +Description: + This file allows the driver for a device to be specified which + will override standard static and dynamic ID matching. When + specified, only a driver with a name matching the value written + to driver_override will have an opportunity to bind to the + device. The override is specified by writing a string to the + driver_override file (echo pci-stub > driver_override) and + may be cleared with an empty string (echo > driver_override). + This returns the device to standard matching rules binding. + Writing to driver_override does not automatically unbind the + device from its current driver or make any attempt to + automatically load the specified driver. If no driver with a + matching name is currently loaded in the kernel, the device + will not bind to any driver. This also allows devices to + opt-out of driver binding using a driver_override name such as + "none". Only a single driver may be specified in the override, + there is no support for parsing delimiters. diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d911e0c1f359..4393c12e9135 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -216,6 +216,13 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, return NULL; } +static const struct pci_device_id pci_device_id_any = { + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, +}; + /** * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure * @drv: the PCI driver to match against @@ -229,18 +236,30 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, struct pci_dev *dev) { struct pci_dynid *dynid; + const struct pci_device_id *found_id = NULL; + + /* When driver_override is set, only bind to the matching driver */ + if (dev->driver_override && strcmp(dev->driver_override, drv->name)) + return NULL; /* Look at the dynamic ids first, before the static ones */ spin_lock(&drv->dynids.lock); list_for_each_entry(dynid, &drv->dynids.list, node) { if (pci_match_one_device(&dynid->id, dev)) { - spin_unlock(&drv->dynids.lock); - return &dynid->id; + found_id = &dynid->id; + break; } } spin_unlock(&drv->dynids.lock); - return pci_match_id(drv->id_table, dev); + if (!found_id) + found_id = pci_match_id(drv->id_table, dev); + + /* driver_override will always match, send a dummy id */ + if (!found_id && dev->driver_override) + found_id = &pci_device_id_any; + + return found_id; } struct drv_dev_and_id { diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 4e0acefb7565..faa4ab554d68 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -499,6 +499,45 @@ static struct device_attribute sriov_numvfs_attr = sriov_numvfs_show, sriov_numvfs_store); #endif /* CONFIG_PCI_IOV */ +static ssize_t driver_override_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = to_pci_dev(dev); + char *driver_override, *old = pdev->driver_override, *cp; + + if (count > PATH_MAX) + return -EINVAL; + + driver_override = kstrndup(buf, count, GFP_KERNEL); + if (!driver_override) + return -ENOMEM; + + cp = strchr(driver_override, '\n'); + if (cp) + *cp = '\0'; + + if (strlen(driver_override)) { + pdev->driver_override = driver_override; + } else { + kfree(driver_override); + pdev->driver_override = NULL; + } + + kfree(old); + + return count; +} + +static ssize_t driver_override_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return sprintf(buf, "%s\n", pdev->driver_override); +} +static DEVICE_ATTR_RW(driver_override); + static struct attribute *pci_dev_attrs[] = { &dev_attr_resource.attr, &dev_attr_vendor.attr, @@ -521,6 +560,7 @@ static struct attribute *pci_dev_attrs[] = { #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI) &dev_attr_d3cold_allowed.attr, #endif + &dev_attr_driver_override.attr, NULL, }; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ef09f5f2fe6c..54268de45f59 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1215,6 +1215,7 @@ static void pci_release_dev(struct device *dev) pci_release_of_node(pci_dev); pcibios_release_device(pci_dev); pci_bus_put(pci_dev->bus); + kfree(pci_dev->driver_override); kfree(pci_dev); } diff --git a/include/linux/pci.h b/include/linux/pci.h index aab57b4abe7f..b72af276f591 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -365,6 +365,7 @@ struct pci_dev { #endif phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */ size_t romlen; /* Length of ROM if it's not from the BAR */ + char *driver_override; /* Driver name to force a match */ }; static inline struct pci_dev *pci_physfn(struct pci_dev *dev)