summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-10-22 00:43:38 +0200
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-10-31 10:17:43 -0700
commit0d52f54e2ef64c189dedc332e680b2eb4a34590a (patch)
tree638b77454f0abdc808d93628d66c219080fc9e58
parent839d8810747bbf39e0a5a7f223b67bffa7945f8d (diff)
PCI / ACPI: Make acpiphp ignore root bridges using PCIe native hotplug
If the kernel has requested control of the PCIe native hotplug feature for a given root complex, the acpiphp driver should not try to handle that root complex and it should leave it to pciehp. Failing to do so causes problems to happen if acpiphp is loaded before pciehp on such systems. To address this issue make find_root_bridges() ignore PCIe root complexes with PCIe native hotplug enabled and make add_bridge() return error code if PCIe native hotplug is enabled for the given root port. This causes acpiphp to refuse to load if PCIe native hotplug is enabled for all complexes and to refuse binding to the root complexes with PCIe native hotplug is enabled. Acked-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 596172b4ae9..fce1c54a0c8 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -459,8 +459,17 @@ static int add_bridge(acpi_handle handle)
{
acpi_status status;
unsigned long long tmp;
+ struct acpi_pci_root *root;
acpi_handle dummy_handle;
+ /*
+ * We shouldn't use this bridge if PCIe native hotplug control has been
+ * granted by the BIOS for it.
+ */
+ root = acpi_pci_find_root(handle);
+ if (root && (root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL))
+ return -ENODEV;
+
/* if the bridge doesn't have _STA, we assume it is always there */
status = acpi_get_handle(handle, "_STA", &dummy_handle);
if (ACPI_SUCCESS(status)) {
@@ -1376,13 +1385,23 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type,
static acpi_status
find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
{
+ struct acpi_pci_root *root;
int *count = (int *)context;
- if (acpi_is_root_bridge(handle)) {
- acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_bridge, NULL);
- (*count)++;
- }
+ if (!acpi_is_root_bridge(handle))
+ return AE_OK;
+
+ root = acpi_pci_find_root(handle);
+ if (!root)
+ return AE_OK;
+
+ if (root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)
+ return AE_OK;
+
+ (*count)++;
+ acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event_bridge, NULL);
+
return AE_OK ;
}