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

PCI hotplug: introduce functions for ACPI slot detection

Some ACPI related PCI hotplug code can be shared among PCI hotplug
drivers. This patch introduces the following functions in
drivers/pci/hotplug/acpi_pcihp.c to share the code, and changes
acpiphp and pciehp to use them.

- int acpi_pci_detect_ejectable(struct pci_bus *pbus)
This checks if the specified PCI bus has ejectable slots.

- int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle)
This checks if the specified handle is ejectable ACPI PCI slot. The
'pbus' parameter is needed to check if 'handle' is PCI related ACPI
object.

This patch also introduces the following inline function in
include/linux/pci-acpi.h, which is useful to get ACPI handle of the
PCI bridge from struct pci_bus of the bridge's secondary bus.

- static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
This returns ACPI handle of the PCI bridge which generates PCI bus
specified by 'pbus'.

Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

authored by

Kenji Kaneshige and committed by
Jesse Barnes
e8c331e9 e046cbd6

+100 -142
+69
drivers/pci/hotplug/acpi_pcihp.c
··· 501 501 } 502 502 EXPORT_SYMBOL_GPL(acpi_root_bridge); 503 503 504 + 505 + static int is_ejectable(acpi_handle handle) 506 + { 507 + acpi_status status; 508 + acpi_handle tmp; 509 + unsigned long long removable; 510 + status = acpi_get_handle(handle, "_ADR", &tmp); 511 + if (ACPI_FAILURE(status)) 512 + return 0; 513 + status = acpi_get_handle(handle, "_EJ0", &tmp); 514 + if (ACPI_SUCCESS(status)) 515 + return 1; 516 + status = acpi_evaluate_integer(handle, "_RMV", NULL, &removable); 517 + if (ACPI_SUCCESS(status) && removable) 518 + return 1; 519 + return 0; 520 + } 521 + 522 + /** 523 + * acpi_pcihp_check_ejectable - check if handle is ejectable ACPI PCI slot 524 + * @pbus: the PCI bus of the PCI slot corresponding to 'handle' 525 + * @handle: ACPI handle to check 526 + * 527 + * Return 1 if handle is ejectable PCI slot, 0 otherwise. 528 + */ 529 + int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle) 530 + { 531 + acpi_handle bridge_handle, parent_handle; 532 + 533 + if (!(bridge_handle = acpi_pci_get_bridge_handle(pbus))) 534 + return 0; 535 + if ((ACPI_FAILURE(acpi_get_parent(handle, &parent_handle)))) 536 + return 0; 537 + if (bridge_handle != parent_handle) 538 + return 0; 539 + return is_ejectable(handle); 540 + } 541 + EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable); 542 + 543 + static acpi_status 544 + check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv) 545 + { 546 + int *found = (int *)context; 547 + if (is_ejectable(handle)) { 548 + *found = 1; 549 + return AE_CTRL_TERMINATE; 550 + } 551 + return AE_OK; 552 + } 553 + 554 + /** 555 + * acpi_pci_detect_ejectable - check if the PCI bus has ejectable slots 556 + * @pbus - PCI bus to scan 557 + * 558 + * Returns 1 if the PCI bus has ACPI based ejectable slots, 0 otherwise. 559 + */ 560 + int acpi_pci_detect_ejectable(struct pci_bus *pbus) 561 + { 562 + acpi_handle handle; 563 + int found = 0; 564 + 565 + if (!(handle = acpi_pci_get_bridge_handle(pbus))) 566 + return 0; 567 + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 568 + check_hotplug, (void *)&found, NULL); 569 + return found; 570 + } 571 + EXPORT_SYMBOL_GPL(acpi_pci_detect_ejectable); 572 + 504 573 module_param(debug_acpi, bool, 0644); 505 574 MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not");
+15 -92
drivers/pci/hotplug/acpiphp_glue.c
··· 46 46 #include <linux/kernel.h> 47 47 #include <linux/pci.h> 48 48 #include <linux/pci_hotplug.h> 49 + #include <linux/pci-acpi.h> 49 50 #include <linux/mutex.h> 50 51 51 52 #include "../pci.h" ··· 63 62 static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); 64 63 static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); 65 64 66 - 67 - /* 68 - * initialization & terminatation routines 69 - */ 70 - 71 - /** 72 - * is_ejectable - determine if a slot is ejectable 73 - * @handle: handle to acpi namespace 74 - * 75 - * Ejectable slot should satisfy at least these conditions: 76 - * 77 - * 1. has _ADR method 78 - * 2. has _EJ0 method or _RMV method 79 - * 80 - * optionally 81 - * 82 - * 1. has _STA method 83 - * 2. has _PS0 method 84 - * 3. has _PS3 method 85 - * 4. .. 86 - */ 87 - static int is_ejectable(acpi_handle handle) 88 - { 89 - acpi_status status; 90 - acpi_handle tmp; 91 - unsigned long long removable; 92 - 93 - status = acpi_get_handle(handle, "_ADR", &tmp); 94 - if (ACPI_FAILURE(status)) 95 - return 0; 96 - 97 - status = acpi_get_handle(handle, "_EJ0", &tmp); 98 - if (ACPI_SUCCESS(status)) 99 - return 1; 100 - 101 - status = acpi_get_handle(handle, "_RMV", &tmp); 102 - if (ACPI_SUCCESS(status)) { 103 - status = acpi_evaluate_integer(handle, "_RMV", NULL, 104 - &removable); 105 - if (ACPI_SUCCESS(status) && removable) 106 - return 1; 107 - } 108 - 109 - return 0; 110 - } 111 - 112 - 113 - /* callback routine to check for the existence of ejectable slots */ 114 - static acpi_status 115 - is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) 116 - { 117 - int *count = (int *)context; 118 - 119 - if (is_ejectable(handle)) { 120 - (*count)++; 121 - /* only one ejectable slot is enough */ 122 - return AE_CTRL_TERMINATE; 123 - } else { 124 - return AE_OK; 125 - } 126 - } 127 - 128 65 /* callback routine to check for the existence of a pci dock device */ 129 66 static acpi_status 130 67 is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) ··· 76 137 return AE_OK; 77 138 } 78 139 } 79 - 80 - 81 - 82 140 83 141 /* 84 142 * the _DCK method can do funny things... and sometimes not ··· 127 191 acpi_status status = AE_OK; 128 192 unsigned long long adr, sun; 129 193 int device, function, retval; 194 + struct pci_bus *pbus = bridge->pci_bus; 130 195 131 - if (!is_ejectable(handle) && !is_dock_device(handle)) 196 + if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) 132 197 return AE_OK; 133 198 134 199 acpi_evaluate_integer(handle, "_ADR", NULL, &adr); ··· 195 258 bridge->nr_slots++; 196 259 197 260 dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", 198 - slot->sun, pci_domain_nr(bridge->pci_bus), 199 - bridge->pci_bus->number, slot->device); 261 + slot->sun, pci_domain_nr(pbus), pbus->number, device); 200 262 retval = acpiphp_register_hotplug_slot(slot); 201 263 if (retval) { 202 264 if (retval == -EBUSY) ··· 212 276 list_add_tail(&newfunc->sibling, &slot->funcs); 213 277 214 278 /* associate corresponding pci_dev */ 215 - newfunc->pci_dev = pci_get_slot(bridge->pci_bus, 216 - PCI_DEVFN(device, function)); 279 + newfunc->pci_dev = pci_get_slot(pbus, PCI_DEVFN(device, function)); 217 280 if (newfunc->pci_dev) { 218 281 slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); 219 282 } ··· 261 326 262 327 263 328 /* see if it's worth looking at this bridge */ 264 - static int detect_ejectable_slots(acpi_handle *bridge_handle) 329 + static int detect_ejectable_slots(struct pci_bus *pbus) 265 330 { 266 - acpi_status status; 267 - int count; 268 - 269 - count = 0; 270 - 271 - /* only check slots defined directly below bridge object */ 272 - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, 273 - is_ejectable_slot, (void *)&count, NULL); 274 - 275 - /* 276 - * we also need to add this bridge if there is a dock bridge or 277 - * other pci device on a dock station (removable) 278 - */ 279 - if (!count) 280 - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, 281 - (u32)1, is_pci_dock_device, (void *)&count, 282 - NULL); 283 - 284 - return count; 331 + int found = acpi_pci_detect_ejectable(pbus); 332 + if (!found) { 333 + acpi_handle bridge_handle = acpi_pci_get_bridge_handle(pbus); 334 + acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, 335 + is_pci_dock_device, (void *)&found, NULL); 336 + } 337 + return found; 285 338 } 286 339 287 340 ··· 479 556 goto out; 480 557 481 558 /* check if this bridge has ejectable slots */ 482 - if ((detect_ejectable_slots(handle) > 0)) { 559 + if ((detect_ejectable_slots(dev->subordinate) > 0)) { 483 560 dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); 484 561 add_p2p_bridge(handle, dev); 485 562 } ··· 540 617 } 541 618 542 619 /* check if this bridge has ejectable slots */ 543 - if (detect_ejectable_slots(handle) > 0) { 620 + if (detect_ejectable_slots(pci_bus) > 0) { 544 621 dbg("found PCI host-bus bridge with hot-pluggable slots\n"); 545 622 add_host_bridge(handle, pci_bus); 546 623 }
+5 -50
drivers/pci/hotplug/pciehp_acpi.c
··· 24 24 */ 25 25 26 26 #include <linux/acpi.h> 27 + #include <linux/pci.h> 28 + #include <linux/pci_hotplug.h> 27 29 #include "pciehp.h" 28 30 29 31 #define PCIEHP_DETECT_PCIE (0) ··· 43 41 " auto(default) - Auto select mode. Use acpi option if duplicate\n" 44 42 " slot ids are found. Otherwise, use pcie option\n"); 45 43 46 - static int is_ejectable(acpi_handle handle) 47 - { 48 - acpi_status status; 49 - acpi_handle tmp; 50 - unsigned long long removable; 51 - status = acpi_get_handle(handle, "_ADR", &tmp); 52 - if (ACPI_FAILURE(status)) 53 - return 0; 54 - status = acpi_get_handle(handle, "_EJ0", &tmp); 55 - if (ACPI_SUCCESS(status)) 56 - return 1; 57 - status = acpi_evaluate_integer(handle, "_RMV", NULL, &removable); 58 - if (ACPI_SUCCESS(status) && removable) 59 - return 1; 60 - return 0; 61 - } 62 - 63 - static acpi_status 64 - check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv) 65 - { 66 - int *found = (int *)context; 67 - if (is_ejectable(handle)) { 68 - *found = 1; 69 - return AE_CTRL_TERMINATE; 70 - } 71 - return AE_OK; 72 - } 73 - 74 - static int pciehp_detect_acpi_slot(struct pci_bus *pbus) 75 - { 76 - acpi_handle handle; 77 - struct pci_dev *pdev = pbus->self; 78 - int found = 0; 79 - 80 - if (!pdev){ 81 - int seg = pci_domain_nr(pbus), busnr = pbus->number; 82 - handle = acpi_get_pci_rootbridge_handle(seg, busnr); 83 - } else 84 - handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); 85 - 86 - if (!handle) 87 - return 0; 88 - 89 - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, 90 - check_hotplug, (void *)&found, NULL); 91 - return found; 92 - } 93 - 94 44 int pciehp_acpi_slot_detection_check(struct pci_dev *dev) 95 45 { 96 46 if (slot_detection_mode != PCIEHP_DETECT_ACPI) 97 47 return 0; 98 - if (pciehp_detect_acpi_slot(dev->subordinate)) 48 + if (acpi_pci_detect_ejectable(dev->subordinate)) 99 49 return 0; 100 50 return -ENODEV; 101 51 } ··· 89 135 u32 slot_cap; 90 136 struct slot *slot, *tmp; 91 137 struct pci_dev *pdev = dev->port; 138 + struct pci_bus *pbus = pdev->subordinate; 92 139 if (!(slot = kzalloc(sizeof(*slot), GFP_KERNEL))) 93 140 return -ENOMEM; 94 141 /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ ··· 104 149 dup_slot_id++; 105 150 } 106 151 list_add_tail(&slot->slot_list, &dummy_slots); 107 - if (!acpi_slot_detected && pciehp_detect_acpi_slot(pdev->subordinate)) 152 + if (!acpi_slot_detected && acpi_pci_detect_ejectable(pbus)) 108 153 acpi_slot_detected = 1; 109 154 return -ENODEV; /* dummy driver always returns error */ 110 155 }
+9
include/linux/pci-acpi.h
··· 60 60 return acpi_get_pci_rootbridge_handle(pci_domain_nr(pdev->bus), 61 61 pdev->bus->number); 62 62 } 63 + 64 + static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus) 65 + { 66 + int seg = pci_domain_nr(pbus), busnr = pbus->number; 67 + struct pci_dev *bridge = pbus->self; 68 + if (bridge) 69 + return DEVICE_ACPI_HANDLE(&(bridge->dev)); 70 + return acpi_get_pci_rootbridge_handle(seg, busnr); 71 + } 63 72 #else 64 73 #if !defined(AE_ERROR) 65 74 typedef u32 acpi_status;
+2
include/linux/pci_hotplug.h
··· 228 228 struct hotplug_params *hpp); 229 229 int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); 230 230 int acpi_root_bridge(acpi_handle handle); 231 + int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle); 232 + int acpi_pci_detect_ejectable(struct pci_bus *pbus); 231 233 #endif 232 234 #endif 233 235