aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2008-12-16 22:09:12 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-01-07 14:13:11 -0500
commite8c331e963c58b83db24b7d0e39e8c07f687dbc6 (patch)
treeda9e7df2441da952dc11bd732b0171d3170fa8bf
parente046cbd6c05ee859244245d7beeac395cd0057b3 (diff)
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>
-rw-r--r--drivers/pci/hotplug/acpi_pcihp.c69
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c107
-rw-r--r--drivers/pci/hotplug/pciehp_acpi.c55
-rw-r--r--include/linux/pci-acpi.h9
-rw-r--r--include/linux/pci_hotplug.h2
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}
502EXPORT_SYMBOL_GPL(acpi_root_bridge); 502EXPORT_SYMBOL_GPL(acpi_root_bridge);
503 503
504
505static 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 */
529int 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}
541EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable);
542
543static acpi_status
544check_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 */
560int 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}
571EXPORT_SYMBOL_GPL(acpi_pci_detect_ejectable);
572
504module_param(debug_acpi, bool, 0644); 573module_param(debug_acpi, bool, 0644);
505MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not"); 574MODULE_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);
62static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); 63static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus);
63static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); 64static 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 */
86static 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 */
113static acpi_status
114is_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 */
128static acpi_status 67static acpi_status
129is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) 68is_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 */
329static int detect_ejectable_slots(acpi_handle *bridge_handle) 264static 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
44static 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
61static acpi_status
62check_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
72static 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
92int pciehp_acpi_slot_detection_check(struct pci_dev *dev) 46int 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
64static 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)
65typedef u32 acpi_status; 74typedef 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);
229int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); 229int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags);
230int acpi_root_bridge(acpi_handle handle); 230int acpi_root_bridge(acpi_handle handle);
231int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle);
232int acpi_pci_detect_ejectable(struct pci_bus *pbus);
231#endif 233#endif
232#endif 234#endif
233 235