aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2013-01-21 16:20:48 -0500
committerBjorn Helgaas <bhelgaas@google.com>2013-01-25 16:50:36 -0500
commit668192b678201d2fff27c6cc76bb003c1ec4a52a (patch)
treeba04f0cb128c7d9cbe44f2050164608921ec7ee9
parent92d8aff3a317fcd6f78ed9ac13dbbaeae8cb11ed (diff)
PCI: acpiphp: Move host bridge hotplug to pci_root.c
The acpiphp driver is confusing because it contains partial support for PCI host bridge hotplug as well as support for hotplug of PCI devices. This patch moves the host bridge hot-add support to pci_root.c and adds hot-remove support in pci_root.c. How to test it: if sci_emu patch is applied, find out root bus number to ACPI root name mapping from dmesg or /sys. To remove root bus: echo "\_SB.PCIB 3" > /sys/kernel/debug/acpi/sci_notify To add back root bus: echo "\_SB.PCIB 1" > /sys/kernel/debug/acpi/sci_notify Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/internal.h1
-rw-r--r--drivers/acpi/pci_root.c124
-rw-r--r--drivers/acpi/scan.c3
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c59
4 files changed, 143 insertions, 44 deletions
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index e050254ae143..0f24148a2b2a 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -68,6 +68,7 @@ struct acpi_ec {
68extern struct acpi_ec *first_ec; 68extern struct acpi_ec *first_ec;
69 69
70int acpi_pci_root_init(void); 70int acpi_pci_root_init(void);
71void acpi_pci_root_hp_init(void);
71int acpi_ec_init(void); 72int acpi_ec_init(void);
72int acpi_ec_ecdt_probe(void); 73int acpi_ec_ecdt_probe(void);
73int acpi_boot_ec_enable(void); 74int acpi_boot_ec_enable(void);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 471b2dcb1c67..1389811aa21b 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -673,3 +673,127 @@ int __init acpi_pci_root_init(void)
673 673
674 return 0; 674 return 0;
675} 675}
676/* Support root bridge hotplug */
677
678static void handle_root_bridge_insertion(acpi_handle handle)
679{
680 struct acpi_device *device;
681
682 if (!acpi_bus_get_device(handle, &device)) {
683 printk(KERN_DEBUG "acpi device exists...\n");
684 return;
685 }
686
687 if (acpi_bus_scan(handle))
688 printk(KERN_ERR "cannot add bridge to acpi list\n");
689}
690
691static void handle_root_bridge_removal(struct acpi_device *device)
692{
693 struct acpi_eject_event *ej_event;
694
695 ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
696 if (!ej_event) {
697 /* Inform firmware the hot-remove operation has error */
698 (void) acpi_evaluate_hotplug_ost(device->handle,
699 ACPI_NOTIFY_EJECT_REQUEST,
700 ACPI_OST_SC_NON_SPECIFIC_FAILURE,
701 NULL);
702 return;
703 }
704
705 ej_event->device = device;
706 ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
707
708 acpi_bus_hot_remove_device(ej_event);
709}
710
711static void _handle_hotplug_event_root(struct work_struct *work)
712{
713 struct acpi_pci_root *root;
714 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER };
715 struct acpi_hp_work *hp_work;
716 acpi_handle handle;
717 u32 type;
718
719 hp_work = container_of(work, struct acpi_hp_work, work);
720 handle = hp_work->handle;
721 type = hp_work->type;
722
723 root = acpi_pci_find_root(handle);
724
725 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
726
727 switch (type) {
728 case ACPI_NOTIFY_BUS_CHECK:
729 /* bus enumerate */
730 printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__,
731 (char *)buffer.pointer);
732 if (!root)
733 handle_root_bridge_insertion(handle);
734
735 break;
736
737 case ACPI_NOTIFY_DEVICE_CHECK:
738 /* device check */
739 printk(KERN_DEBUG "%s: Device check notify on %s\n", __func__,
740 (char *)buffer.pointer);
741 if (!root)
742 handle_root_bridge_insertion(handle);
743 break;
744
745 case ACPI_NOTIFY_EJECT_REQUEST:
746 /* request device eject */
747 printk(KERN_DEBUG "%s: Device eject notify on %s\n", __func__,
748 (char *)buffer.pointer);
749 if (root)
750 handle_root_bridge_removal(root->device);
751 break;
752 default:
753 printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n",
754 type, (char *)buffer.pointer);
755 break;
756 }
757
758 kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
759 kfree(buffer.pointer);
760}
761
762static void handle_hotplug_event_root(acpi_handle handle, u32 type,
763 void *context)
764{
765 alloc_acpi_hp_work(handle, type, context,
766 _handle_hotplug_event_root);
767}
768
769static acpi_status __init
770find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
771{
772 char objname[64];
773 struct acpi_buffer buffer = { .length = sizeof(objname),
774 .pointer = objname };
775 int *count = (int *)context;
776
777 if (!acpi_is_root_bridge(handle))
778 return AE_OK;
779
780 (*count)++;
781
782 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
783
784 acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
785 handle_hotplug_event_root, NULL);
786 printk(KERN_DEBUG "acpi root: %s notify handler installed\n", objname);
787
788 return AE_OK;
789}
790
791void __init acpi_pci_root_hp_init(void)
792{
793 int num = 0;
794
795 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
796 ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);
797
798 printk(KERN_DEBUG "Found %d acpi root devices\n", num);
799}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 7c43bdc36abc..bc2f33790e83 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1706,5 +1706,8 @@ int __init acpi_scan_init(void)
1706 } 1706 }
1707 1707
1708 acpi_update_all_gpes(); 1708 acpi_update_all_gpes();
1709
1710 acpi_pci_root_hp_init();
1711
1709 return 0; 1712 return 0;
1710} 1713}
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index bf338d2ff371..c4a6301009f2 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -543,10 +543,13 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
543 acpi_status status; 543 acpi_status status;
544 acpi_handle handle = bridge->handle; 544 acpi_handle handle = bridge->handle;
545 545
546 status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 546 if (bridge->type != BRIDGE_TYPE_HOST) {
547 status = acpi_remove_notify_handler(handle,
548 ACPI_SYSTEM_NOTIFY,
547 handle_hotplug_event_bridge); 549 handle_hotplug_event_bridge);
548 if (ACPI_FAILURE(status)) 550 if (ACPI_FAILURE(status))
549 err("failed to remove notify handler\n"); 551 err("failed to remove notify handler\n");
552 }
550 553
551 if ((bridge->type != BRIDGE_TYPE_HOST) && 554 if ((bridge->type != BRIDGE_TYPE_HOST) &&
552 ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) { 555 ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) {
@@ -630,9 +633,6 @@ static void remove_bridge(struct acpi_pci_root *root)
630 bridge = acpiphp_handle_to_bridge(handle); 633 bridge = acpiphp_handle_to_bridge(handle);
631 if (bridge) 634 if (bridge)
632 cleanup_bridge(bridge); 635 cleanup_bridge(bridge);
633 else
634 acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
635 handle_hotplug_event_bridge);
636} 636}
637 637
638static int power_on_slot(struct acpiphp_slot *slot) 638static int power_on_slot(struct acpiphp_slot *slot)
@@ -1123,18 +1123,12 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
1123} 1123}
1124 1124
1125/* Program resources in newly inserted bridge */ 1125/* Program resources in newly inserted bridge */
1126static int acpiphp_configure_bridge (acpi_handle handle) 1126static int acpiphp_configure_p2p_bridge(acpi_handle handle)
1127{ 1127{
1128 struct pci_bus *bus; 1128 struct pci_dev *pdev = acpi_get_pci_dev(handle);
1129 struct pci_bus *bus = pdev->subordinate;
1129 1130
1130 if (acpi_is_root_bridge(handle)) { 1131 pci_dev_put(pdev);
1131 struct acpi_pci_root *root = acpi_pci_find_root(handle);
1132 bus = root->bus;
1133 } else {
1134 struct pci_dev *pdev = acpi_get_pci_dev(handle);
1135 bus = pdev->subordinate;
1136 pci_dev_put(pdev);
1137 }
1138 1132
1139 pci_bus_size_bridges(bus); 1133 pci_bus_size_bridges(bus);
1140 pci_bus_assign_resources(bus); 1134 pci_bus_assign_resources(bus);
@@ -1144,7 +1138,7 @@ static int acpiphp_configure_bridge (acpi_handle handle)
1144 return 0; 1138 return 0;
1145} 1139}
1146 1140
1147static void handle_bridge_insertion(acpi_handle handle, u32 type) 1141static void handle_p2p_bridge_insertion(acpi_handle handle, u32 type)
1148{ 1142{
1149 struct acpi_device *device; 1143 struct acpi_device *device;
1150 1144
@@ -1162,8 +1156,8 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type)
1162 err("ACPI device object missing\n"); 1156 err("ACPI device object missing\n");
1163 return; 1157 return;
1164 } 1158 }
1165 if (!acpiphp_configure_bridge(handle)) 1159 if (!acpiphp_configure_p2p_bridge(handle))
1166 add_bridge(handle); 1160 add_p2p_bridge(handle);
1167 else 1161 else
1168 err("cannot configure and start bridge\n"); 1162 err("cannot configure and start bridge\n");
1169 1163
@@ -1221,7 +1215,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
1221 1215
1222 if (acpi_bus_get_device(handle, &device)) { 1216 if (acpi_bus_get_device(handle, &device)) {
1223 /* This bridge must have just been physically inserted */ 1217 /* This bridge must have just been physically inserted */
1224 handle_bridge_insertion(handle, type); 1218 handle_p2p_bridge_insertion(handle, type);
1225 goto out; 1219 goto out;
1226 } 1220 }
1227 1221
@@ -1396,21 +1390,6 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type,
1396 alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func); 1390 alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
1397} 1391}
1398 1392
1399static acpi_status
1400find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
1401{
1402 int *count = (int *)context;
1403
1404 if (!acpi_is_root_bridge(handle))
1405 return AE_OK;
1406
1407 (*count)++;
1408 acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
1409 handle_hotplug_event_bridge, NULL);
1410
1411 return AE_OK ;
1412}
1413
1414static struct acpi_pci_driver acpi_pci_hp_driver = { 1393static struct acpi_pci_driver acpi_pci_hp_driver = {
1415 .add = add_bridge, 1394 .add = add_bridge,
1416 .remove = remove_bridge, 1395 .remove = remove_bridge,
@@ -1421,15 +1400,7 @@ static struct acpi_pci_driver acpi_pci_hp_driver = {
1421 */ 1400 */
1422int __init acpiphp_glue_init(void) 1401int __init acpiphp_glue_init(void)
1423{ 1402{
1424 int num = 0; 1403 acpi_pci_register_driver(&acpi_pci_hp_driver);
1425
1426 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
1427 ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);
1428
1429 if (num <= 0)
1430 return -1;
1431 else
1432 acpi_pci_register_driver(&acpi_pci_hp_driver);
1433 1404
1434 return 0; 1405 return 0;
1435} 1406}