aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorMUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com>2006-03-22 00:49:20 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-19 17:13:22 -0400
commit551bcb75b3d9f23348a524210ccfff26d865e425 (patch)
treefd4990605440ffff56c041ebef87624d225a6c08 /drivers/pci
parent92c9be95549632da09088320f202fa5c05b21ddf (diff)
[PATCH] acpiphp: hotplug slot hotplug
o hotplug slots add When the hot-added PCI device is p2p bridge, acpiphp calls find_p2p_bridge() to add hotplug slots. o hotplug slots remove When the hot-removing PCI device is p2p bridge, acpiphp calls cleanup_p2p_bridge() to remove hotplug slots. o notify handler exchange When the p2p bridge is added, acpiphp changes the notify hanlder. If no bridge device is inserted into the hotpluggable PCI slot, acpiphp installs the notify handler for function. After the p2p bridge hot-add, acpiphp has to install the notify handler for bridge. Because, the role of the handlers are not same. The hot-remove case is ditto. Signed-off-by: MUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/acpiphp.h5
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c126
2 files changed, 122 insertions, 9 deletions
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 467ac70a46ff..17a93f890dba 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -75,6 +75,10 @@ struct acpiphp_bridge {
75 struct list_head list; 75 struct list_head list;
76 acpi_handle handle; 76 acpi_handle handle;
77 struct acpiphp_slot *slots; 77 struct acpiphp_slot *slots;
78
79 /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
80 struct acpiphp_func *func;
81
78 int type; 82 int type;
79 int nr_slots; 83 int nr_slots;
80 84
@@ -122,6 +126,7 @@ struct acpiphp_slot {
122 */ 126 */
123struct acpiphp_func { 127struct acpiphp_func {
124 struct acpiphp_slot *slot; /* parent */ 128 struct acpiphp_slot *slot; /* parent */
129 struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */
125 130
126 struct list_head sibling; 131 struct list_head sibling;
127 struct pci_dev *pci_dev; 132 struct pci_dev *pci_dev;
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index fadd264b64c3..631efce3a6ce 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -319,6 +319,13 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
319 319
320 /* install notify handler */ 320 /* install notify handler */
321 if (bridge->type != BRIDGE_TYPE_HOST) { 321 if (bridge->type != BRIDGE_TYPE_HOST) {
322 if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
323 status = acpi_remove_notify_handler(bridge->func->handle,
324 ACPI_SYSTEM_NOTIFY,
325 handle_hotplug_event_func);
326 if (ACPI_FAILURE(status))
327 err("failed to remove notify handler\n");
328 }
322 status = acpi_install_notify_handler(bridge->handle, 329 status = acpi_install_notify_handler(bridge->handle,
323 ACPI_SYSTEM_NOTIFY, 330 ACPI_SYSTEM_NOTIFY,
324 handle_hotplug_event_bridge, 331 handle_hotplug_event_bridge,
@@ -331,6 +338,66 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
331} 338}
332 339
333 340
341/* find acpiphp_func from acpiphp_bridge */
342static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
343{
344 struct list_head *node, *l;
345 struct acpiphp_bridge *bridge;
346 struct acpiphp_slot *slot;
347 struct acpiphp_func *func;
348
349 list_for_each(node, &bridge_list) {
350 bridge = list_entry(node, struct acpiphp_bridge, list);
351 for (slot = bridge->slots; slot; slot = slot->next) {
352 list_for_each(l, &slot->funcs) {
353 func = list_entry(l, struct acpiphp_func,
354 sibling);
355 if (func->handle == handle)
356 return func;
357 }
358 }
359 }
360
361 return NULL;
362}
363
364
365static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge)
366{
367 acpi_handle dummy_handle;
368
369 if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
370 "_STA", &dummy_handle)))
371 bridge->flags |= BRIDGE_HAS_STA;
372
373 if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
374 "_EJ0", &dummy_handle)))
375 bridge->flags |= BRIDGE_HAS_EJ0;
376
377 if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
378 "_PS0", &dummy_handle)))
379 bridge->flags |= BRIDGE_HAS_PS0;
380
381 if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
382 "_PS3", &dummy_handle)))
383 bridge->flags |= BRIDGE_HAS_PS3;
384
385 /* is this ejectable p2p bridge? */
386 if (bridge->flags & BRIDGE_HAS_EJ0) {
387 struct acpiphp_func *func;
388
389 dbg("found ejectable p2p bridge\n");
390
391 /* make link between PCI bridge and PCI function */
392 func = acpiphp_bridge_handle_to_function(bridge->handle);
393 if (!func)
394 return;
395 bridge->func = func;
396 func->bridge = bridge;
397 }
398}
399
400
334/* allocate and initialize host bridge data structure */ 401/* allocate and initialize host bridge data structure */
335static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) 402static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus)
336{ 403{
@@ -364,6 +431,7 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev)
364 431
365 bridge->type = BRIDGE_TYPE_P2P; 432 bridge->type = BRIDGE_TYPE_P2P;
366 bridge->handle = handle; 433 bridge->handle = handle;
434 config_p2p_bridge_flags(bridge);
367 435
368 bridge->pci_dev = pci_dev_get(pci_dev); 436 bridge->pci_dev = pci_dev_get(pci_dev);
369 bridge->pci_bus = pci_dev->subordinate; 437 bridge->pci_bus = pci_dev->subordinate;
@@ -423,7 +491,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
423 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 491 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
424 find_p2p_bridge, dev->subordinate, NULL); 492 find_p2p_bridge, dev->subordinate, NULL);
425 if (ACPI_FAILURE(status)) 493 if (ACPI_FAILURE(status))
426 warn("find_p2p_bridge faied (error code = 0x%x)\n", status); 494 warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
427 495
428 out: 496 out:
429 pci_dev_put(dev); 497 pci_dev_put(dev);
@@ -486,7 +554,7 @@ static int add_bridge(acpi_handle handle)
486 find_p2p_bridge, pci_bus, NULL); 554 find_p2p_bridge, pci_bus, NULL);
487 555
488 if (ACPI_FAILURE(status)) 556 if (ACPI_FAILURE(status))
489 warn("find_p2p_bridge faied (error code = 0x%x)\n",status); 557 warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
490 558
491 return 0; 559 return 0;
492} 560}
@@ -516,6 +584,16 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
516 if (ACPI_FAILURE(status)) 584 if (ACPI_FAILURE(status))
517 err("failed to remove notify handler\n"); 585 err("failed to remove notify handler\n");
518 586
587 if ((bridge->type != BRIDGE_TYPE_HOST) &&
588 ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) {
589 status = acpi_install_notify_handler(bridge->func->handle,
590 ACPI_SYSTEM_NOTIFY,
591 handle_hotplug_event_func,
592 bridge->func);
593 if (ACPI_FAILURE(status))
594 err("failed to install interrupt notify handler\n");
595 }
596
519 slot = bridge->slots; 597 slot = bridge->slots;
520 while (slot) { 598 while (slot) {
521 struct acpiphp_slot *next = slot->next; 599 struct acpiphp_slot *next = slot->next;
@@ -549,6 +627,11 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
549{ 627{
550 struct acpiphp_bridge *bridge; 628 struct acpiphp_bridge *bridge;
551 629
630 /* cleanup p2p bridges under this P2P bridge
631 in a depth-first manner */
632 acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
633 cleanup_p2p_bridge, NULL, NULL);
634
552 if (!(bridge = acpiphp_handle_to_bridge(handle))) 635 if (!(bridge = acpiphp_handle_to_bridge(handle)))
553 return AE_OK; 636 return AE_OK;
554 cleanup_bridge(bridge); 637 cleanup_bridge(bridge);
@@ -559,15 +642,14 @@ static void remove_bridge(acpi_handle handle)
559{ 642{
560 struct acpiphp_bridge *bridge; 643 struct acpiphp_bridge *bridge;
561 644
645 /* cleanup p2p bridges under this host bridge
646 in a depth-first manner */
647 acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
648 (u32)1, cleanup_p2p_bridge, NULL, NULL);
649
562 bridge = acpiphp_handle_to_bridge(handle); 650 bridge = acpiphp_handle_to_bridge(handle);
563 if (bridge) { 651 if (bridge)
564 cleanup_bridge(bridge); 652 cleanup_bridge(bridge);
565 } else {
566 /* clean-up p2p bridges under this host bridge */
567 acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
568 ACPI_UINT32_MAX, cleanup_p2p_bridge,
569 NULL, NULL);
570 }
571} 653}
572 654
573static struct pci_dev * get_apic_pci_info(acpi_handle handle) 655static struct pci_dev * get_apic_pci_info(acpi_handle handle)
@@ -881,6 +963,7 @@ static int enable_device(struct acpiphp_slot *slot)
881 struct acpiphp_func *func; 963 struct acpiphp_func *func;
882 int retval = 0; 964 int retval = 0;
883 int num, max, pass; 965 int num, max, pass;
966 acpi_status status;
884 967
885 if (slot->flags & SLOT_ENABLED) 968 if (slot->flags & SLOT_ENABLED)
886 goto err_exit; 969 goto err_exit;
@@ -933,6 +1016,17 @@ static int enable_device(struct acpiphp_slot *slot)
933 func = list_entry(l, struct acpiphp_func, sibling); 1016 func = list_entry(l, struct acpiphp_func, sibling);
934 func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 1017 func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
935 func->function)); 1018 func->function));
1019 if (!func->pci_dev)
1020 continue;
1021
1022 if (func->pci_dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
1023 func->pci_dev->hdr_type != PCI_HEADER_TYPE_CARDBUS)
1024 continue;
1025
1026 status = find_p2p_bridge(func->handle, (u32)1, bus, NULL);
1027 if (ACPI_FAILURE(status))
1028 warn("find_p2p_bridge failed (error code = 0x%x)\n",
1029 status);
936 } 1030 }
937 1031
938 slot->flags |= SLOT_ENABLED; 1032 slot->flags |= SLOT_ENABLED;
@@ -958,6 +1052,13 @@ static int disable_device(struct acpiphp_slot *slot)
958 list_for_each (l, &slot->funcs) { 1052 list_for_each (l, &slot->funcs) {
959 func = list_entry(l, struct acpiphp_func, sibling); 1053 func = list_entry(l, struct acpiphp_func, sibling);
960 1054
1055 if (func->bridge) {
1056 /* cleanup p2p bridges under this P2P bridge */
1057 cleanup_p2p_bridge(func->bridge->handle,
1058 (u32)1, NULL, NULL);
1059 func->bridge = NULL;
1060 }
1061
961 acpiphp_bus_trim(func->handle); 1062 acpiphp_bus_trim(func->handle);
962 /* try to remove anyway. 1063 /* try to remove anyway.
963 * acpiphp_bus_add might have been failed */ 1064 * acpiphp_bus_add might have been failed */
@@ -1292,6 +1393,13 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
1292 case ACPI_NOTIFY_EJECT_REQUEST: 1393 case ACPI_NOTIFY_EJECT_REQUEST:
1293 /* request device eject */ 1394 /* request device eject */
1294 dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); 1395 dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
1396 if ((bridge->type != BRIDGE_TYPE_HOST) &&
1397 (bridge->flags & BRIDGE_HAS_EJ0)) {
1398 struct acpiphp_slot *slot;
1399 slot = bridge->func->slot;
1400 if (!acpiphp_disable_slot(slot))
1401 acpiphp_eject_slot(slot);
1402 }
1295 break; 1403 break;
1296 1404
1297 case ACPI_NOTIFY_FREQUENCY_MISMATCH: 1405 case ACPI_NOTIFY_FREQUENCY_MISMATCH: