Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Gary Hade <garyhade@us.ibm.com>
Cc: <lcm@us.ibm.com>
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Gary Hade and committed by
Greg Kroah-Hartman
0bbd6424 9ef2241b

+46 -2
+46 -2
drivers/pci/hotplug/acpiphp_glue.c
··· 1505 1505 * ACPI event handlers 1506 1506 */ 1507 1507 1508 + static acpi_status 1509 + count_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) 1510 + { 1511 + int *count = (int *)context; 1512 + struct acpiphp_bridge *bridge; 1513 + 1514 + bridge = acpiphp_handle_to_bridge(handle); 1515 + if (bridge) 1516 + (*count)++; 1517 + return AE_OK ; 1518 + } 1519 + 1520 + static acpi_status 1521 + check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) 1522 + { 1523 + struct acpiphp_bridge *bridge; 1524 + char objname[64]; 1525 + struct acpi_buffer buffer = { .length = sizeof(objname), 1526 + .pointer = objname }; 1527 + 1528 + bridge = acpiphp_handle_to_bridge(handle); 1529 + if (bridge) { 1530 + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 1531 + dbg("%s: re-enumerating slots under %s\n", 1532 + __FUNCTION__, objname); 1533 + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 1534 + acpiphp_check_bridge(bridge); 1535 + } 1536 + return AE_OK ; 1537 + } 1538 + 1508 1539 /** 1509 1540 * handle_hotplug_event_bridge - handle ACPI event on bridges 1510 1541 * ··· 1553 1522 struct acpi_buffer buffer = { .length = sizeof(objname), 1554 1523 .pointer = objname }; 1555 1524 struct acpi_device *device; 1525 + int num_sub_bridges = 0; 1556 1526 1557 1527 if (acpi_bus_get_device(handle, &device)) { 1558 1528 /* This bridge must have just been physically inserted */ ··· 1562 1530 } 1563 1531 1564 1532 bridge = acpiphp_handle_to_bridge(handle); 1565 - if (!bridge) { 1533 + if (type == ACPI_NOTIFY_BUS_CHECK) { 1534 + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX, 1535 + count_sub_bridges, &num_sub_bridges, NULL); 1536 + } 1537 + 1538 + if (!bridge && !num_sub_bridges) { 1566 1539 err("cannot get bridge info\n"); 1567 1540 return; 1568 1541 } ··· 1578 1541 case ACPI_NOTIFY_BUS_CHECK: 1579 1542 /* bus re-enumerate */ 1580 1543 dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); 1581 - acpiphp_check_bridge(bridge); 1544 + if (bridge) { 1545 + dbg("%s: re-enumerating slots under %s\n", 1546 + __FUNCTION__, objname); 1547 + acpiphp_check_bridge(bridge); 1548 + } 1549 + if (num_sub_bridges) 1550 + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1551 + ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL); 1582 1552 break; 1583 1553 1584 1554 case ACPI_NOTIFY_DEVICE_CHECK: