diff options
-rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 69 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 107 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_acpi.c | 55 | ||||
-rw-r--r-- | include/linux/pci-acpi.h | 9 | ||||
-rw-r--r-- | include/linux/pci_hotplug.h | 2 |
5 files changed, 100 insertions, 142 deletions
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index e17ef54f0efc..c62ab8d240aa 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c | |||
@@ -501,5 +501,74 @@ int acpi_root_bridge(acpi_handle handle) | |||
501 | } | 501 | } |
502 | EXPORT_SYMBOL_GPL(acpi_root_bridge); | 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 | module_param(debug_acpi, bool, 0644); | 573 | module_param(debug_acpi, bool, 0644); |
505 | MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not"); | 574 | MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not"); |
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 7a5760426897..f09b1010d477 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/kernel.h> | 46 | #include <linux/kernel.h> |
47 | #include <linux/pci.h> | 47 | #include <linux/pci.h> |
48 | #include <linux/pci_hotplug.h> | 48 | #include <linux/pci_hotplug.h> |
49 | #include <linux/pci-acpi.h> | ||
49 | #include <linux/mutex.h> | 50 | #include <linux/mutex.h> |
50 | 51 | ||
51 | #include "../pci.h" | 52 | #include "../pci.h" |
@@ -62,68 +63,6 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus); | |||
62 | static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); | 63 | static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); |
63 | static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); | 64 | static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); |
64 | 65 | ||
65 | |||
66 | /* | ||
67 | * initialization & terminatation routines | ||
68 | */ | ||
69 | |||
70 | /** | ||
71 | * is_ejectable - determine if a slot is ejectable | ||
72 | * @handle: handle to acpi namespace | ||
73 | * | ||
74 | * Ejectable slot should satisfy at least these conditions: | ||
75 | * | ||
76 | * 1. has _ADR method | ||
77 | * 2. has _EJ0 method or _RMV method | ||
78 | * | ||
79 | * optionally | ||
80 | * | ||
81 | * 1. has _STA method | ||
82 | * 2. has _PS0 method | ||
83 | * 3. has _PS3 method | ||
84 | * 4. .. | ||
85 | */ | ||
86 | static int is_ejectable(acpi_handle handle) | ||
87 | { | ||
88 | acpi_status status; | ||
89 | acpi_handle tmp; | ||
90 | unsigned long long removable; | ||
91 | |||
92 | status = acpi_get_handle(handle, "_ADR", &tmp); | ||
93 | if (ACPI_FAILURE(status)) | ||
94 | return 0; | ||
95 | |||
96 | status = acpi_get_handle(handle, "_EJ0", &tmp); | ||
97 | if (ACPI_SUCCESS(status)) | ||
98 | return 1; | ||
99 | |||
100 | status = acpi_get_handle(handle, "_RMV", &tmp); | ||
101 | if (ACPI_SUCCESS(status)) { | ||
102 | status = acpi_evaluate_integer(handle, "_RMV", NULL, | ||
103 | &removable); | ||
104 | if (ACPI_SUCCESS(status) && removable) | ||
105 | return 1; | ||
106 | } | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | |||
112 | /* callback routine to check for the existence of ejectable slots */ | ||
113 | static acpi_status | ||
114 | is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
115 | { | ||
116 | int *count = (int *)context; | ||
117 | |||
118 | if (is_ejectable(handle)) { | ||
119 | (*count)++; | ||
120 | /* only one ejectable slot is enough */ | ||
121 | return AE_CTRL_TERMINATE; | ||
122 | } else { | ||
123 | return AE_OK; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | /* callback routine to check for the existence of a pci dock device */ | 66 | /* callback routine to check for the existence of a pci dock device */ |
128 | static acpi_status | 67 | static acpi_status |
129 | is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) | 68 | is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) |
@@ -138,9 +77,6 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
138 | } | 77 | } |
139 | } | 78 | } |
140 | 79 | ||
141 | |||
142 | |||
143 | |||
144 | /* | 80 | /* |
145 | * the _DCK method can do funny things... and sometimes not | 81 | * the _DCK method can do funny things... and sometimes not |
146 | * hah-hah funny. | 82 | * hah-hah funny. |
@@ -191,8 +127,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
191 | acpi_status status = AE_OK; | 127 | acpi_status status = AE_OK; |
192 | unsigned long long adr, sun; | 128 | unsigned long long adr, sun; |
193 | int device, function, retval; | 129 | int device, function, retval; |
130 | struct pci_bus *pbus = bridge->pci_bus; | ||
194 | 131 | ||
195 | if (!is_ejectable(handle) && !is_dock_device(handle)) | 132 | if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) |
196 | return AE_OK; | 133 | return AE_OK; |
197 | 134 | ||
198 | acpi_evaluate_integer(handle, "_ADR", NULL, &adr); | 135 | acpi_evaluate_integer(handle, "_ADR", NULL, &adr); |
@@ -258,8 +195,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
258 | bridge->nr_slots++; | 195 | bridge->nr_slots++; |
259 | 196 | ||
260 | dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", | 197 | dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", |
261 | slot->sun, pci_domain_nr(bridge->pci_bus), | 198 | slot->sun, pci_domain_nr(pbus), pbus->number, device); |
262 | bridge->pci_bus->number, slot->device); | ||
263 | retval = acpiphp_register_hotplug_slot(slot); | 199 | retval = acpiphp_register_hotplug_slot(slot); |
264 | if (retval) { | 200 | if (retval) { |
265 | if (retval == -EBUSY) | 201 | if (retval == -EBUSY) |
@@ -276,8 +212,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
276 | list_add_tail(&newfunc->sibling, &slot->funcs); | 212 | list_add_tail(&newfunc->sibling, &slot->funcs); |
277 | 213 | ||
278 | /* associate corresponding pci_dev */ | 214 | /* associate corresponding pci_dev */ |
279 | newfunc->pci_dev = pci_get_slot(bridge->pci_bus, | 215 | newfunc->pci_dev = pci_get_slot(pbus, PCI_DEVFN(device, function)); |
280 | PCI_DEVFN(device, function)); | ||
281 | if (newfunc->pci_dev) { | 216 | if (newfunc->pci_dev) { |
282 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); | 217 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); |
283 | } | 218 | } |
@@ -326,27 +261,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
326 | 261 | ||
327 | 262 | ||
328 | /* see if it's worth looking at this bridge */ | 263 | /* see if it's worth looking at this bridge */ |
329 | static int detect_ejectable_slots(acpi_handle *bridge_handle) | 264 | static int detect_ejectable_slots(struct pci_bus *pbus) |
330 | { | 265 | { |
331 | acpi_status status; | 266 | int found = acpi_pci_detect_ejectable(pbus); |
332 | int count; | 267 | if (!found) { |
333 | 268 | acpi_handle bridge_handle = acpi_pci_get_bridge_handle(pbus); | |
334 | count = 0; | 269 | acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, |
335 | 270 | is_pci_dock_device, (void *)&found, NULL); | |
336 | /* only check slots defined directly below bridge object */ | 271 | } |
337 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, | 272 | return found; |
338 | is_ejectable_slot, (void *)&count, NULL); | ||
339 | |||
340 | /* | ||
341 | * we also need to add this bridge if there is a dock bridge or | ||
342 | * other pci device on a dock station (removable) | ||
343 | */ | ||
344 | if (!count) | ||
345 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, | ||
346 | (u32)1, is_pci_dock_device, (void *)&count, | ||
347 | NULL); | ||
348 | |||
349 | return count; | ||
350 | } | 273 | } |
351 | 274 | ||
352 | 275 | ||
@@ -556,7 +479,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
556 | goto out; | 479 | goto out; |
557 | 480 | ||
558 | /* check if this bridge has ejectable slots */ | 481 | /* check if this bridge has ejectable slots */ |
559 | if ((detect_ejectable_slots(handle) > 0)) { | 482 | if ((detect_ejectable_slots(dev->subordinate) > 0)) { |
560 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); | 483 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); |
561 | add_p2p_bridge(handle, dev); | 484 | add_p2p_bridge(handle, dev); |
562 | } | 485 | } |
@@ -617,7 +540,7 @@ static int add_bridge(acpi_handle handle) | |||
617 | } | 540 | } |
618 | 541 | ||
619 | /* check if this bridge has ejectable slots */ | 542 | /* check if this bridge has ejectable slots */ |
620 | if (detect_ejectable_slots(handle) > 0) { | 543 | if (detect_ejectable_slots(pci_bus) > 0) { |
621 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); | 544 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); |
622 | add_host_bridge(handle, pci_bus); | 545 | add_host_bridge(handle, pci_bus); |
623 | } | 546 | } |
diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c index 88a5c57f2e5b..438d795f9fe3 100644 --- a/drivers/pci/hotplug/pciehp_acpi.c +++ b/drivers/pci/hotplug/pciehp_acpi.c | |||
@@ -24,6 +24,8 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/acpi.h> | 26 | #include <linux/acpi.h> |
27 | #include <linux/pci.h> | ||
28 | #include <linux/pci_hotplug.h> | ||
27 | #include "pciehp.h" | 29 | #include "pciehp.h" |
28 | 30 | ||
29 | #define PCIEHP_DETECT_PCIE (0) | 31 | #define PCIEHP_DETECT_PCIE (0) |
@@ -41,59 +43,11 @@ MODULE_PARM_DESC(pciehp_detect_mode, | |||
41 | " auto(default) - Auto select mode. Use acpi option if duplicate\n" | 43 | " auto(default) - Auto select mode. Use acpi option if duplicate\n" |
42 | " slot ids are found. Otherwise, use pcie option\n"); | 44 | " slot ids are found. Otherwise, use pcie option\n"); |
43 | 45 | ||
44 | static int is_ejectable(acpi_handle handle) | ||
45 | { | ||
46 | acpi_status status; | ||
47 | acpi_handle tmp; | ||
48 | unsigned long long removable; | ||
49 | status = acpi_get_handle(handle, "_ADR", &tmp); | ||
50 | if (ACPI_FAILURE(status)) | ||
51 | return 0; | ||
52 | status = acpi_get_handle(handle, "_EJ0", &tmp); | ||
53 | if (ACPI_SUCCESS(status)) | ||
54 | return 1; | ||
55 | status = acpi_evaluate_integer(handle, "_RMV", NULL, &removable); | ||
56 | if (ACPI_SUCCESS(status) && removable) | ||
57 | return 1; | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static acpi_status | ||
62 | check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
63 | { | ||
64 | int *found = (int *)context; | ||
65 | if (is_ejectable(handle)) { | ||
66 | *found = 1; | ||
67 | return AE_CTRL_TERMINATE; | ||
68 | } | ||
69 | return AE_OK; | ||
70 | } | ||
71 | |||
72 | static int pciehp_detect_acpi_slot(struct pci_bus *pbus) | ||
73 | { | ||
74 | acpi_handle handle; | ||
75 | struct pci_dev *pdev = pbus->self; | ||
76 | int found = 0; | ||
77 | |||
78 | if (!pdev){ | ||
79 | int seg = pci_domain_nr(pbus), busnr = pbus->number; | ||
80 | handle = acpi_get_pci_rootbridge_handle(seg, busnr); | ||
81 | } else | ||
82 | handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); | ||
83 | |||
84 | if (!handle) | ||
85 | return 0; | ||
86 | |||
87 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | ||
88 | check_hotplug, (void *)&found, NULL); | ||
89 | return found; | ||
90 | } | ||
91 | |||
92 | int pciehp_acpi_slot_detection_check(struct pci_dev *dev) | 46 | int pciehp_acpi_slot_detection_check(struct pci_dev *dev) |
93 | { | 47 | { |
94 | if (slot_detection_mode != PCIEHP_DETECT_ACPI) | 48 | if (slot_detection_mode != PCIEHP_DETECT_ACPI) |
95 | return 0; | 49 | return 0; |
96 | if (pciehp_detect_acpi_slot(dev->subordinate)) | 50 | if (acpi_pci_detect_ejectable(dev->subordinate)) |
97 | return 0; | 51 | return 0; |
98 | return -ENODEV; | 52 | return -ENODEV; |
99 | } | 53 | } |
@@ -135,6 +89,7 @@ static int __init dummy_probe(struct pcie_device *dev, | |||
135 | u32 slot_cap; | 89 | u32 slot_cap; |
136 | struct slot *slot, *tmp; | 90 | struct slot *slot, *tmp; |
137 | struct pci_dev *pdev = dev->port; | 91 | struct pci_dev *pdev = dev->port; |
92 | struct pci_bus *pbus = pdev->subordinate; | ||
138 | if (!(slot = kzalloc(sizeof(*slot), GFP_KERNEL))) | 93 | if (!(slot = kzalloc(sizeof(*slot), GFP_KERNEL))) |
139 | return -ENOMEM; | 94 | return -ENOMEM; |
140 | /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ | 95 | /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ |
@@ -149,7 +104,7 @@ static int __init dummy_probe(struct pcie_device *dev, | |||
149 | dup_slot_id++; | 104 | dup_slot_id++; |
150 | } | 105 | } |
151 | list_add_tail(&slot->slot_list, &dummy_slots); | 106 | list_add_tail(&slot->slot_list, &dummy_slots); |
152 | if (!acpi_slot_detected && pciehp_detect_acpi_slot(pdev->subordinate)) | 107 | if (!acpi_slot_detected && acpi_pci_detect_ejectable(pbus)) |
153 | acpi_slot_detected = 1; | 108 | acpi_slot_detected = 1; |
154 | return -ENODEV; /* dummy driver always returns error */ | 109 | return -ENODEV; /* dummy driver always returns error */ |
155 | } | 110 | } |
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 871e096e0fbc..042c166f65d5 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h | |||
@@ -60,6 +60,15 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) | |||
60 | return acpi_get_pci_rootbridge_handle(pci_domain_nr(pdev->bus), | 60 | return acpi_get_pci_rootbridge_handle(pci_domain_nr(pdev->bus), |
61 | pdev->bus->number); | 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 | #else | 72 | #else |
64 | #if !defined(AE_ERROR) | 73 | #if !defined(AE_ERROR) |
65 | typedef u32 acpi_status; | 74 | typedef u32 acpi_status; |
diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index a00bd1a0f156..f7cc204fab07 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h | |||
@@ -228,6 +228,8 @@ extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, | |||
228 | struct hotplug_params *hpp); | 228 | struct hotplug_params *hpp); |
229 | int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); | 229 | int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); |
230 | int acpi_root_bridge(acpi_handle handle); | 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 | #endif | 233 | #endif |
232 | #endif | 234 | #endif |
233 | 235 | ||