diff options
author | Jiang Liu <liuj97@gmail.com> | 2013-04-12 01:44:26 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2013-04-12 18:52:01 -0400 |
commit | 3b63aaa70e1ccc4b66d60acc78da09700706a703 (patch) | |
tree | 6255864d51d65ab0d833e197a9ef9080d83a68de /drivers/pci/hotplug | |
parent | 6037a803b05eef9943fb64982e19964007fb7478 (diff) |
PCI: acpiphp: Do not use ACPI PCI subdriver mechanism
Previously the acpiphp driver registered itself as an ACPI PCI subdriver,
so its callbacks were invoked when creating/destroying PCI root
buses to manage ACPI-based PCI hotplug slots. But it doesn't handle
P2P bridge hotplug events, so it will cause strange behaviour if there
are hotplug slots associated with a hot-removed P2P bridge.
This patch fixes this issue by:
1) Directly hooking into PCI core to update hotplug slot devices when
creating/destroying PCI buses through:
pci_{add|remove}_bus() -> acpi_pci_{add|remove}_bus()
2) Getting rid of unused ACPI PCI subdriver-related code
It also cleans up unused code in the acpiphp driver.
[bhelgaas: keep acpi_pci_add_bus() stub for CONFIG_ACPI=n]
Signed-off-by: Jiang Liu <jiang.liu@huawei.com>
Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Yinghai Lu <yinghai@kernel.org>
Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
Cc: Toshi Kani <toshi.kani@hp.com>
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 3 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_core.c | 13 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 288 |
3 files changed, 57 insertions, 247 deletions
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index b06ae681d5b7..abd48d309ad0 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h | |||
@@ -119,7 +119,6 @@ struct acpiphp_slot { | |||
119 | */ | 119 | */ |
120 | struct acpiphp_func { | 120 | struct acpiphp_func { |
121 | struct acpiphp_slot *slot; /* parent */ | 121 | struct acpiphp_slot *slot; /* parent */ |
122 | struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */ | ||
123 | 122 | ||
124 | struct list_head sibling; | 123 | struct list_head sibling; |
125 | struct notifier_block nb; | 124 | struct notifier_block nb; |
@@ -176,8 +175,6 @@ extern int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot); | |||
176 | extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); | 175 | extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); |
177 | 176 | ||
178 | /* acpiphp_glue.c */ | 177 | /* acpiphp_glue.c */ |
179 | extern int acpiphp_glue_init (void); | ||
180 | extern void acpiphp_glue_exit (void); | ||
181 | typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); | 178 | typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); |
182 | 179 | ||
183 | extern int acpiphp_enable_slot (struct acpiphp_slot *slot); | 180 | extern int acpiphp_enable_slot (struct acpiphp_slot *slot); |
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 81adbfa4df1b..ca8127950fcd 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c | |||
@@ -37,6 +37,7 @@ | |||
37 | 37 | ||
38 | #include <linux/kernel.h> | 38 | #include <linux/kernel.h> |
39 | #include <linux/pci.h> | 39 | #include <linux/pci.h> |
40 | #include <linux/pci-acpi.h> | ||
40 | #include <linux/pci_hotplug.h> | 41 | #include <linux/pci_hotplug.h> |
41 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
42 | #include <linux/smp.h> | 43 | #include <linux/smp.h> |
@@ -354,19 +355,9 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot) | |||
354 | } | 355 | } |
355 | 356 | ||
356 | 357 | ||
357 | static int __init acpiphp_init(void) | 358 | void __init acpiphp_init(void) |
358 | { | 359 | { |
359 | info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n", | 360 | info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n", |
360 | acpiphp_disabled ? ", disabled by user; please report a bug" | 361 | acpiphp_disabled ? ", disabled by user; please report a bug" |
361 | : ""); | 362 | : ""); |
362 | |||
363 | if (acpi_pci_disabled || acpiphp_disabled) | ||
364 | return 0; | ||
365 | |||
366 | /* read all the ACPI info from the system */ | ||
367 | /* initialize internal data structure etc. */ | ||
368 | return acpiphp_glue_init(); | ||
369 | } | 363 | } |
370 | |||
371 | |||
372 | module_init(acpiphp_init); | ||
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 718464f8fd40..20db4d6564a8 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -157,6 +157,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
157 | int device, function, retval; | 157 | int device, function, retval; |
158 | struct pci_bus *pbus = bridge->pci_bus; | 158 | struct pci_bus *pbus = bridge->pci_bus; |
159 | struct pci_dev *pdev; | 159 | struct pci_dev *pdev; |
160 | u32 val; | ||
160 | 161 | ||
161 | if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) | 162 | if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) |
162 | return AE_OK; | 163 | return AE_OK; |
@@ -249,11 +250,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
249 | newfunc->slot = slot; | 250 | newfunc->slot = slot; |
250 | list_add_tail(&newfunc->sibling, &slot->funcs); | 251 | list_add_tail(&newfunc->sibling, &slot->funcs); |
251 | 252 | ||
252 | pdev = pci_get_slot(pbus, PCI_DEVFN(device, function)); | 253 | if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function), |
253 | if (pdev) { | 254 | &val, 60*1000)) |
254 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); | 255 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); |
255 | pci_dev_put(pdev); | ||
256 | } | ||
257 | 256 | ||
258 | if (is_dock_device(handle)) { | 257 | if (is_dock_device(handle)) { |
259 | /* we don't want to call this device's _EJ0 | 258 | /* we don't want to call this device's _EJ0 |
@@ -366,148 +365,6 @@ static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle | |||
366 | } | 365 | } |
367 | 366 | ||
368 | 367 | ||
369 | static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) | ||
370 | { | ||
371 | acpi_handle dummy_handle; | ||
372 | struct acpiphp_func *func; | ||
373 | |||
374 | if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
375 | "_EJ0", &dummy_handle))) { | ||
376 | bridge->flags |= BRIDGE_HAS_EJ0; | ||
377 | |||
378 | dbg("found ejectable p2p bridge\n"); | ||
379 | |||
380 | /* make link between PCI bridge and PCI function */ | ||
381 | func = acpiphp_bridge_handle_to_function(bridge->handle); | ||
382 | if (!func) | ||
383 | return; | ||
384 | bridge->func = func; | ||
385 | func->bridge = bridge; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | |||
390 | /* allocate and initialize host bridge data structure */ | ||
391 | static void add_host_bridge(struct acpi_pci_root *root) | ||
392 | { | ||
393 | struct acpiphp_bridge *bridge; | ||
394 | acpi_handle handle = root->device->handle; | ||
395 | |||
396 | bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); | ||
397 | if (bridge == NULL) | ||
398 | return; | ||
399 | |||
400 | bridge->handle = handle; | ||
401 | |||
402 | bridge->pci_bus = root->bus; | ||
403 | |||
404 | init_bridge_misc(bridge); | ||
405 | } | ||
406 | |||
407 | |||
408 | /* allocate and initialize PCI-to-PCI bridge data structure */ | ||
409 | static void add_p2p_bridge(acpi_handle *handle) | ||
410 | { | ||
411 | struct acpiphp_bridge *bridge; | ||
412 | |||
413 | bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); | ||
414 | if (bridge == NULL) { | ||
415 | err("out of memory\n"); | ||
416 | return; | ||
417 | } | ||
418 | |||
419 | bridge->handle = handle; | ||
420 | config_p2p_bridge_flags(bridge); | ||
421 | |||
422 | bridge->pci_dev = acpi_get_pci_dev(handle); | ||
423 | bridge->pci_bus = bridge->pci_dev->subordinate; | ||
424 | if (!bridge->pci_bus) { | ||
425 | err("This is not a PCI-to-PCI bridge!\n"); | ||
426 | goto err; | ||
427 | } | ||
428 | |||
429 | /* | ||
430 | * Grab a ref to the subordinate PCI bus in case the bus is | ||
431 | * removed via PCI core logical hotplug. The ref pins the bus | ||
432 | * (which we access during module unload). | ||
433 | */ | ||
434 | get_device(&bridge->pci_bus->dev); | ||
435 | |||
436 | init_bridge_misc(bridge); | ||
437 | return; | ||
438 | err: | ||
439 | pci_dev_put(bridge->pci_dev); | ||
440 | kfree(bridge); | ||
441 | return; | ||
442 | } | ||
443 | |||
444 | |||
445 | /* callback routine to find P2P bridges */ | ||
446 | static acpi_status | ||
447 | find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
448 | { | ||
449 | acpi_status status; | ||
450 | struct pci_dev *dev; | ||
451 | |||
452 | dev = acpi_get_pci_dev(handle); | ||
453 | if (!dev || !dev->subordinate) | ||
454 | goto out; | ||
455 | |||
456 | /* check if this bridge has ejectable slots */ | ||
457 | if ((detect_ejectable_slots(handle) > 0)) { | ||
458 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); | ||
459 | add_p2p_bridge(handle); | ||
460 | } | ||
461 | |||
462 | /* search P2P bridges under this p2p bridge */ | ||
463 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | ||
464 | find_p2p_bridge, NULL, NULL, NULL); | ||
465 | if (ACPI_FAILURE(status)) | ||
466 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); | ||
467 | |||
468 | out: | ||
469 | pci_dev_put(dev); | ||
470 | return AE_OK; | ||
471 | } | ||
472 | |||
473 | |||
474 | /* find hot-pluggable slots, and then find P2P bridge */ | ||
475 | static int add_bridge(struct acpi_pci_root *root) | ||
476 | { | ||
477 | acpi_status status; | ||
478 | unsigned long long tmp; | ||
479 | acpi_handle dummy_handle; | ||
480 | acpi_handle handle = root->device->handle; | ||
481 | |||
482 | /* if the bridge doesn't have _STA, we assume it is always there */ | ||
483 | status = acpi_get_handle(handle, "_STA", &dummy_handle); | ||
484 | if (ACPI_SUCCESS(status)) { | ||
485 | status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); | ||
486 | if (ACPI_FAILURE(status)) { | ||
487 | dbg("%s: _STA evaluation failure\n", __func__); | ||
488 | return 0; | ||
489 | } | ||
490 | if ((tmp & ACPI_STA_DEVICE_FUNCTIONING) == 0) | ||
491 | /* don't register this object */ | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | /* check if this bridge has ejectable slots */ | ||
496 | if (detect_ejectable_slots(handle) > 0) { | ||
497 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); | ||
498 | add_host_bridge(root); | ||
499 | } | ||
500 | |||
501 | /* search P2P bridges under this host bridge */ | ||
502 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | ||
503 | find_p2p_bridge, NULL, NULL, NULL); | ||
504 | |||
505 | if (ACPI_FAILURE(status)) | ||
506 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) | 368 | static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) |
512 | { | 369 | { |
513 | struct acpiphp_bridge *bridge; | 370 | struct acpiphp_bridge *bridge; |
@@ -567,56 +424,12 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
567 | slot = next; | 424 | slot = next; |
568 | } | 425 | } |
569 | 426 | ||
570 | /* | 427 | put_device(&bridge->pci_bus->dev); |
571 | * Only P2P bridges have a pci_dev | ||
572 | */ | ||
573 | if (bridge->pci_dev) | ||
574 | put_device(&bridge->pci_bus->dev); | ||
575 | |||
576 | pci_dev_put(bridge->pci_dev); | 428 | pci_dev_put(bridge->pci_dev); |
577 | list_del(&bridge->list); | 429 | list_del(&bridge->list); |
578 | kfree(bridge); | 430 | kfree(bridge); |
579 | } | 431 | } |
580 | 432 | ||
581 | static acpi_status | ||
582 | cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
583 | { | ||
584 | struct acpiphp_bridge *bridge; | ||
585 | |||
586 | /* cleanup p2p bridges under this P2P bridge | ||
587 | in a depth-first manner */ | ||
588 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | ||
589 | cleanup_p2p_bridge, NULL, NULL, NULL); | ||
590 | |||
591 | bridge = acpiphp_handle_to_bridge(handle); | ||
592 | if (bridge) | ||
593 | cleanup_bridge(bridge); | ||
594 | |||
595 | return AE_OK; | ||
596 | } | ||
597 | |||
598 | static void remove_bridge(struct acpi_pci_root *root) | ||
599 | { | ||
600 | struct acpiphp_bridge *bridge; | ||
601 | acpi_handle handle = root->device->handle; | ||
602 | |||
603 | /* cleanup p2p bridges under this host bridge | ||
604 | in a depth-first manner */ | ||
605 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, | ||
606 | (u32)1, cleanup_p2p_bridge, NULL, NULL, NULL); | ||
607 | |||
608 | /* | ||
609 | * On root bridges with hotplug slots directly underneath (ie, | ||
610 | * no p2p bridge between), we call cleanup_bridge(). | ||
611 | * | ||
612 | * The else clause cleans up root bridges that either had no | ||
613 | * hotplug slots at all, or had a p2p bridge underneath. | ||
614 | */ | ||
615 | bridge = acpiphp_handle_to_bridge(handle); | ||
616 | if (bridge) | ||
617 | cleanup_bridge(bridge); | ||
618 | } | ||
619 | |||
620 | static int power_on_slot(struct acpiphp_slot *slot) | 433 | static int power_on_slot(struct acpiphp_slot *slot) |
621 | { | 434 | { |
622 | acpi_status status; | 435 | acpi_status status; |
@@ -798,6 +611,7 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) | |||
798 | } | 611 | } |
799 | } | 612 | } |
800 | } | 613 | } |
614 | |||
801 | /** | 615 | /** |
802 | * enable_device - enable, configure a slot | 616 | * enable_device - enable, configure a slot |
803 | * @slot: slot to be enabled | 617 | * @slot: slot to be enabled |
@@ -812,7 +626,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) | |||
812 | struct acpiphp_func *func; | 626 | struct acpiphp_func *func; |
813 | int retval = 0; | 627 | int retval = 0; |
814 | int num, max, pass; | 628 | int num, max, pass; |
815 | acpi_status status; | ||
816 | 629 | ||
817 | if (slot->flags & SLOT_ENABLED) | 630 | if (slot->flags & SLOT_ENABLED) |
818 | goto err_exit; | 631 | goto err_exit; |
@@ -867,18 +680,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) | |||
867 | slot->flags &= (~SLOT_ENABLED); | 680 | slot->flags &= (~SLOT_ENABLED); |
868 | continue; | 681 | continue; |
869 | } | 682 | } |
870 | |||
871 | if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE && | ||
872 | dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) { | ||
873 | pci_dev_put(dev); | ||
874 | continue; | ||
875 | } | ||
876 | |||
877 | status = find_p2p_bridge(func->handle, (u32)1, bus, NULL); | ||
878 | if (ACPI_FAILURE(status)) | ||
879 | warn("find_p2p_bridge failed (error code = 0x%x)\n", | ||
880 | status); | ||
881 | pci_dev_put(dev); | ||
882 | } | 683 | } |
883 | 684 | ||
884 | 685 | ||
@@ -912,16 +713,6 @@ static int disable_device(struct acpiphp_slot *slot) | |||
912 | { | 713 | { |
913 | struct acpiphp_func *func; | 714 | struct acpiphp_func *func; |
914 | struct pci_dev *pdev; | 715 | struct pci_dev *pdev; |
915 | struct pci_bus *bus = slot->bridge->pci_bus; | ||
916 | |||
917 | list_for_each_entry(func, &slot->funcs, sibling) { | ||
918 | if (func->bridge) { | ||
919 | /* cleanup p2p bridges under this P2P bridge */ | ||
920 | cleanup_p2p_bridge(func->bridge->handle, | ||
921 | (u32)1, NULL, NULL); | ||
922 | func->bridge = NULL; | ||
923 | } | ||
924 | } | ||
925 | 716 | ||
926 | /* | 717 | /* |
927 | * enable_device() enumerates all functions in this device via | 718 | * enable_device() enumerates all functions in this device via |
@@ -940,7 +731,6 @@ static int disable_device(struct acpiphp_slot *slot) | |||
940 | 731 | ||
941 | slot->flags &= (~SLOT_ENABLED); | 732 | slot->flags &= (~SLOT_ENABLED); |
942 | 733 | ||
943 | err_exit: | ||
944 | return 0; | 734 | return 0; |
945 | } | 735 | } |
946 | 736 | ||
@@ -1287,30 +1077,62 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, | |||
1287 | alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func); | 1077 | alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func); |
1288 | } | 1078 | } |
1289 | 1079 | ||
1290 | static struct acpi_pci_driver acpi_pci_hp_driver = { | 1080 | /* |
1291 | .add = add_bridge, | 1081 | * Create hotplug slots for the PCI bus. |
1292 | .remove = remove_bridge, | 1082 | * It should always return 0 to avoid skipping following notifiers. |
1293 | }; | ||
1294 | |||
1295 | /** | ||
1296 | * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures | ||
1297 | */ | 1083 | */ |
1298 | int __init acpiphp_glue_init(void) | 1084 | void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle) |
1299 | { | 1085 | { |
1300 | acpi_pci_register_driver(&acpi_pci_hp_driver); | 1086 | acpi_handle dummy_handle; |
1087 | struct acpiphp_bridge *bridge; | ||
1301 | 1088 | ||
1302 | return 0; | 1089 | if (acpiphp_disabled) |
1303 | } | 1090 | return; |
1304 | 1091 | ||
1092 | if (detect_ejectable_slots(handle) <= 0) | ||
1093 | return; | ||
1305 | 1094 | ||
1306 | /** | 1095 | bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); |
1307 | * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures | 1096 | if (bridge == NULL) { |
1308 | * | 1097 | err("out of memory\n"); |
1309 | * This function frees all data allocated in acpiphp_glue_init(). | 1098 | return; |
1310 | */ | 1099 | } |
1311 | void acpiphp_glue_exit(void) | 1100 | |
1101 | bridge->handle = handle; | ||
1102 | bridge->pci_dev = pci_dev_get(bus->self); | ||
1103 | bridge->pci_bus = bus; | ||
1104 | |||
1105 | /* | ||
1106 | * Grab a ref to the subordinate PCI bus in case the bus is | ||
1107 | * removed via PCI core logical hotplug. The ref pins the bus | ||
1108 | * (which we access during module unload). | ||
1109 | */ | ||
1110 | get_device(&bus->dev); | ||
1111 | |||
1112 | if (!pci_is_root_bus(bridge->pci_bus) && | ||
1113 | ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
1114 | "_EJ0", &dummy_handle))) { | ||
1115 | dbg("found ejectable p2p bridge\n"); | ||
1116 | bridge->flags |= BRIDGE_HAS_EJ0; | ||
1117 | bridge->func = acpiphp_bridge_handle_to_function(handle); | ||
1118 | } | ||
1119 | |||
1120 | init_bridge_misc(bridge); | ||
1121 | } | ||
1122 | |||
1123 | /* Destroy hotplug slots associated with the PCI bus */ | ||
1124 | void acpiphp_remove_slots(struct pci_bus *bus) | ||
1312 | { | 1125 | { |
1313 | acpi_pci_unregister_driver(&acpi_pci_hp_driver); | 1126 | struct acpiphp_bridge *bridge, *tmp; |
1127 | |||
1128 | if (acpiphp_disabled) | ||
1129 | return; | ||
1130 | |||
1131 | list_for_each_entry_safe(bridge, tmp, &bridge_list, list) | ||
1132 | if (bridge->pci_bus == bus) { | ||
1133 | cleanup_bridge(bridge); | ||
1134 | break; | ||
1135 | } | ||
1314 | } | 1136 | } |
1315 | 1137 | ||
1316 | /** | 1138 | /** |