提交 0bbd6424 编写于 作者: G Gary Hade 提交者: Greg Kroah-Hartman

PCI: hotplug: acpiphp: avoid acpiphp "cannot get bridge info" PCI hotplug failure

On some systems, the ACPI bus check event can reference a bridge that is
higher in the ACPI hierarchy than the bridge immediately above the
hotplug PCI slot into which an adapter was just inserted.  The current
'acpiphp' code expects the bus check event to reference the bridge
immediately above the slot that received the adapter so the hotplug
operation can fail on these systems with the message "acpiphp_glue:
cannot get bridge info".  This change fixes the problem by
re-enumerating all slots that lie below the bridge referenced by the bus
check event, including those slots that may be located under lower level
PCI-to-PCI bridge(s).
Signed-off-by: NGary Hade <garyhade@us.ibm.com>
Cc: <lcm@us.ibm.com>
Signed-off-by: NKristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 9ef2241b
......@@ -1505,6 +1505,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
*
......@@ -1522,6 +1553,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 */
......@@ -1530,7 +1562,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;
}
......@@ -1541,7 +1578,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:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册