From: Konrad Rzeszutek <konradr@redhat.com> Date: Thu, 19 Jul 2007 12:20:15 -0400 Subject: [hotplug] acpiphp: 'cannot get bridge info' with PCIe Message-id: 20070719162015.GA24616@mars.boston.redhat.com O-Subject: [RHEL5 U1 PATCH] RHBZ #248571: LTC36136-acpiphp 'cannot get bridge info' hotplug failure with PCIe adapter on x3850 Bugzilla: 248571 RHBZ#: ------ https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=248571 Description: ------------ A hot-add operation involving a PCIe adapter fails on the x3850 with the ACPI PCI hotplug driver 'acpiphp' message "acpiphp_glue: cannot get bridge info". Root cause: On the x3850 the ACPI bus check event generated when a PCIe adapter is inserted/latched references the ACPI object for the PCI host bridge that is higher in the ACPI hierarchy than the PCI-to-PCI bridge immediately above slot receiving the adapter. This is allowed by the ACPI spec but the current 'acpiphp' code expects the bus check event to always reference the bridge immediately above the slot. If there are no slots immediately below the bridge against which the event was received the code does not currently explore below this bridge and re-enumerate slots that may be located under lower level PCI-to-PCI bridge(s). RHEL Version Found: ------------------ RHEL5 U1 kABI status: ------------ No symbols changed/deleted or added. Brew build: ----------- Built on all platforms (scratch build: 878512). Upstream Status: ---------------- The proposed fix has been signed off by Kristen Carlson Accardi and Greg Kroah-Hartman and is now in Greg's 2.6 tree. tree: http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/ file: pci-hotplug-acpiphp-avoid-acpiphp-cannot-get-bridge-info-pci-hotplug-failure.patch Test Status: ------------ Tested on IBM x3850 in Westford, MA. Without the patch the PCI-E hotplug doesn't work. With the patch the cards get their driver loaded. I would like to test this on other non-IBM boxes that have PCI-E hotplug capability - anybody know specifically which machines can do this? Proposed Patch: --------------- This patch builds/applies cleanly on top of 2.6.18-34. Signed-off-by: Gary Hade <garyhade@us.ibm.com> Acked-by: Pete Zaitcev <zaitcev@redhat.com> --- drivers/pci/hotplug/acpiphp_glue.c | 48 ++++++++++++++++++++++++++++++++++- 1 files changed, 46 insertions(+), 2 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 8930f8e..a67702f 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1503,6 +1503,37 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type) * ACPI event handlers */ +static acpi_status +count_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + struct acpiphp_bridge *bridge; + + bridge = acpiphp_handle_to_bridge(handle); + if (bridge) + (*count)++; + return AE_OK ; +} + +static acpi_status +check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + struct acpiphp_bridge *bridge; + char objname[64]; + struct acpi_buffer buffer = { .length = sizeof(objname), + .pointer = objname }; + + bridge = acpiphp_handle_to_bridge(handle); + if (bridge) { + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + dbg("%s: re-enumerating slots under %s\n", + __FUNCTION__, objname); + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + acpiphp_check_bridge(bridge); + } + return AE_OK ; +} + /** * handle_hotplug_event_bridge - handle ACPI event on bridges * @@ -1520,6 +1551,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; struct acpi_device *device; + int num_sub_bridges = 0; if (acpi_bus_get_device(handle, &device)) { /* This bridge must have just been physically inserted */ @@ -1528,7 +1560,12 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont } bridge = acpiphp_handle_to_bridge(handle); - if (!bridge) { + if (type == ACPI_NOTIFY_BUS_CHECK) { + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX, + count_sub_bridges, &num_sub_bridges, NULL); + } + + if (!bridge && !num_sub_bridges) { err("cannot get bridge info\n"); return; } @@ -1539,7 +1576,14 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); - acpiphp_check_bridge(bridge); + if (bridge) { + dbg("%s: re-enumerating slots under %s\n", + __FUNCTION__, objname); + acpiphp_check_bridge(bridge); + } + if (num_sub_bridges) + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL); break; case ACPI_NOTIFY_DEVICE_CHECK: -- 1.5.3.5.645.gbb47