diff options
| author | Yinghai Lu <yinghai@kernel.org> | 2013-05-07 13:06:03 -0400 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2013-05-17 16:12:06 -0400 |
| commit | 3f327e39b4b8f760c331bb2836735be6d83fbf53 (patch) | |
| tree | c2ebbf36764c554c31d82a82a6afb174c8e2b698 | |
| parent | f722406faae2d073cc1d01063d1123c35425939e (diff) | |
PCI: acpiphp: Re-enumerate devices when host bridge receives Bus Check
When a PCI host bridge device receives a Bus Check notification, we
must re-enumerate starting with the bridge to discover changes (devices
that have been added or removed).
Prior to 668192b678 ("PCI: acpiphp: Move host bridge hotplug to
pci_root.c"), this happened in _handle_hotplug_event_bridge(). After that
commit, _handle_hotplug_event_bridge() is not installed for host bridges,
and the host bridge notify handler, _handle_hotplug_event_root() did not
re-enumerate.
This patch adds re-enumeration to _handle_hotplug_event_root().
This fixes cases where we don't notice the addition or removal of
PCI devices, e.g., the PCI-to-USB ExpressCard in the bugzilla below.
[bhelgaas: changelog, references]
Reference: https://lkml.kernel.org/r/CAAh6nkmbKR3HTqm5ommevsBwhL_u0N8Rk7Wsms_LfP=nBgKNew@mail.gmail.com
Reference: https://bugzilla.kernel.org/show_bug.cgi?id=57961
Reported-by: Gavin Guo <tuffkidtt@gmail.com>
Tested-by: Gavin Guo <tuffkidtt@gmail.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Jiang Liu <jiang.liu@huawei.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
CC: stable@vger.kernel.org # v3.9+
| -rw-r--r-- | drivers/acpi/pci_root.c | 4 | ||||
| -rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 14 | ||||
| -rw-r--r-- | include/linux/pci-acpi.h | 2 |
3 files changed, 19 insertions, 1 deletions
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1dd6f6c85874..e427dc516c76 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
| @@ -641,7 +641,9 @@ static void _handle_hotplug_event_root(struct work_struct *work) | |||
| 641 | /* bus enumerate */ | 641 | /* bus enumerate */ |
| 642 | printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__, | 642 | printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__, |
| 643 | (char *)buffer.pointer); | 643 | (char *)buffer.pointer); |
| 644 | if (!root) | 644 | if (root) |
| 645 | acpiphp_check_host_bridge(handle); | ||
| 646 | else | ||
| 645 | handle_root_bridge_insertion(handle); | 647 | handle_root_bridge_insertion(handle); |
| 646 | 648 | ||
| 647 | break; | 649 | break; |
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 96fed19c6d90..716aa93fff76 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
| @@ -950,6 +950,20 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
| 950 | return AE_OK ; | 950 | return AE_OK ; |
| 951 | } | 951 | } |
| 952 | 952 | ||
| 953 | void acpiphp_check_host_bridge(acpi_handle handle) | ||
| 954 | { | ||
| 955 | struct acpiphp_bridge *bridge; | ||
| 956 | |||
| 957 | bridge = acpiphp_handle_to_bridge(handle); | ||
| 958 | if (bridge) { | ||
| 959 | acpiphp_check_bridge(bridge); | ||
| 960 | put_bridge(bridge); | ||
| 961 | } | ||
| 962 | |||
| 963 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, | ||
| 964 | ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); | ||
| 965 | } | ||
| 966 | |||
| 953 | static void _handle_hotplug_event_bridge(struct work_struct *work) | 967 | static void _handle_hotplug_event_bridge(struct work_struct *work) |
| 954 | { | 968 | { |
| 955 | struct acpiphp_bridge *bridge; | 969 | struct acpiphp_bridge *bridge; |
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 81b31613eb25..170447977278 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h | |||
| @@ -60,11 +60,13 @@ static inline void acpi_pci_slot_remove(struct pci_bus *bus) { } | |||
| 60 | void acpiphp_init(void); | 60 | void acpiphp_init(void); |
| 61 | void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle); | 61 | void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle); |
| 62 | void acpiphp_remove_slots(struct pci_bus *bus); | 62 | void acpiphp_remove_slots(struct pci_bus *bus); |
| 63 | void acpiphp_check_host_bridge(acpi_handle handle); | ||
| 63 | #else | 64 | #else |
| 64 | static inline void acpiphp_init(void) { } | 65 | static inline void acpiphp_init(void) { } |
| 65 | static inline void acpiphp_enumerate_slots(struct pci_bus *bus, | 66 | static inline void acpiphp_enumerate_slots(struct pci_bus *bus, |
| 66 | acpi_handle handle) { } | 67 | acpi_handle handle) { } |
| 67 | static inline void acpiphp_remove_slots(struct pci_bus *bus) { } | 68 | static inline void acpiphp_remove_slots(struct pci_bus *bus) { } |
| 69 | static inline void acpiphp_check_host_bridge(acpi_handle handle) { } | ||
| 68 | #endif | 70 | #endif |
| 69 | 71 | ||
| 70 | #else /* CONFIG_ACPI */ | 72 | #else /* CONFIG_ACPI */ |
