Commit e8c331e963c58b83db24b7d0e39e8c07f687dbc6

Authored by Kenji Kaneshige
Committed by Jesse Barnes
1 parent e046cbd6c0

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>

Showing 5 changed files with 100 additions and 142 deletions Side-by-side Diff

drivers/pci/hotplug/acpi_pcihp.c
... ... @@ -501,6 +501,75 @@
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");
drivers/pci/hotplug/acpiphp_glue.c
... ... @@ -46,6 +46,7 @@
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"
... ... @@ -62,68 +63,6 @@
62 63 static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus);
63 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 66 /* callback routine to check for the existence of a pci dock device */
128 67 static acpi_status
129 68 is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
... ... @@ -138,9 +77,6 @@
138 77 }
139 78 }
140 79  
141   -
142   -
143   -
144 80 /*
145 81 * the _DCK method can do funny things... and sometimes not
146 82 * hah-hah funny.
147 83  
... ... @@ -191,8 +127,9 @@
191 127 acpi_status status = AE_OK;
192 128 unsigned long long adr, sun;
193 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 133 return AE_OK;
197 134  
198 135 acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
... ... @@ -258,8 +195,7 @@
258 195 bridge->nr_slots++;
259 196  
260 197 dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
261   - slot->sun, pci_domain_nr(bridge->pci_bus),
262   - bridge->pci_bus->number, slot->device);
  198 + slot->sun, pci_domain_nr(pbus), pbus->number, device);
263 199 retval = acpiphp_register_hotplug_slot(slot);
264 200 if (retval) {
265 201 if (retval == -EBUSY)
... ... @@ -276,8 +212,7 @@
276 212 list_add_tail(&newfunc->sibling, &slot->funcs);
277 213  
278 214 /* associate corresponding pci_dev */
279   - newfunc->pci_dev = pci_get_slot(bridge->pci_bus,
280   - PCI_DEVFN(device, function));
  215 + newfunc->pci_dev = pci_get_slot(pbus, PCI_DEVFN(device, function));
281 216 if (newfunc->pci_dev) {
282 217 slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
283 218 }
284 219  
... ... @@ -326,27 +261,15 @@
326 261  
327 262  
328 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;
332   - int count;
333   -
334   - count = 0;
335   -
336   - /* only check slots defined directly below bridge object */
337   - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
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;
  266 + int found = acpi_pci_detect_ejectable(pbus);
  267 + if (!found) {
  268 + acpi_handle bridge_handle = acpi_pci_get_bridge_handle(pbus);
  269 + acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
  270 + is_pci_dock_device, (void *)&found, NULL);
  271 + }
  272 + return found;
350 273 }
351 274  
352 275  
... ... @@ -556,7 +479,7 @@
556 479 goto out;
557 480  
558 481 /* check if this bridge has ejectable slots */
559   - if ((detect_ejectable_slots(handle) > 0)) {
  482 + if ((detect_ejectable_slots(dev->subordinate) > 0)) {
560 483 dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
561 484 add_p2p_bridge(handle, dev);
562 485 }
... ... @@ -617,7 +540,7 @@
617 540 }
618 541  
619 542 /* check if this bridge has ejectable slots */
620   - if (detect_ejectable_slots(handle) > 0) {
  543 + if (detect_ejectable_slots(pci_bus) > 0) {
621 544 dbg("found PCI host-bus bridge with hot-pluggable slots\n");
622 545 add_host_bridge(handle, pci_bus);
623 546 }
drivers/pci/hotplug/pciehp_acpi.c
... ... @@ -24,6 +24,8 @@
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)
30 32  
... ... @@ -41,59 +43,11 @@
41 43 " auto(default) - Auto select mode. Use acpi option if duplicate\n"
42 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 46 int pciehp_acpi_slot_detection_check(struct pci_dev *dev)
93 47 {
94 48 if (slot_detection_mode != PCIEHP_DETECT_ACPI)
95 49 return 0;
96   - if (pciehp_detect_acpi_slot(dev->subordinate))
  50 + if (acpi_pci_detect_ejectable(dev->subordinate))
97 51 return 0;
98 52 return -ENODEV;
99 53 }
... ... @@ -135,6 +89,7 @@
135 89 u32 slot_cap;
136 90 struct slot *slot, *tmp;
137 91 struct pci_dev *pdev = dev->port;
  92 + struct pci_bus *pbus = pdev->subordinate;
138 93 if (!(slot = kzalloc(sizeof(*slot), GFP_KERNEL)))
139 94 return -ENOMEM;
140 95 /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
... ... @@ -149,7 +104,7 @@
149 104 dup_slot_id++;
150 105 }
151 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 108 acpi_slot_detected = 1;
154 109 return -ENODEV; /* dummy driver always returns error */
155 110 }
include/linux/pci-acpi.h
... ... @@ -60,6 +60,15 @@
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;
include/linux/pci_hotplug.h
... ... @@ -228,6 +228,8 @@
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