diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2013-04-16 12:37:22 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2013-04-16 12:37:22 -0400 |
commit | a3b6bbd5774c13dab89d72f79976ba762913b2f2 (patch) | |
tree | e646832db42284e97e6b4d1edc616ce06e0fd407 /drivers/pci/hotplug | |
parent | 30e22b2337be44f4363fa52858d1ca7be6794ee8 (diff) | |
parent | c309dbb4debb714566e4cf0d5d4e4023c3c4ff2f (diff) |
Merge branch 'pci/jiang-subdrivers' into next
* pci/jiang-subdrivers:
PCI/ACPI: Remove support of ACPI PCI subdrivers
PCI: acpiphp: Protect acpiphp data structures from concurrent updates
PCI: acpiphp: Use normal list to simplify implementation
PCI: acpiphp: Do not use ACPI PCI subdriver mechanism
PCI: acpiphp: Convert acpiphp to be builtin only, not modular
PCI/ACPI: Handle PCI slot devices when creating/destroying PCI buses
x86/PCI: Implement pcibios_{add|remove}_bus() hooks
ia64/PCI: Implement pcibios_{add|remove}_bus() hooks
PCI/ACPI: Prepare stub functions to handle ACPI PCI (hotplug) slots
PCI: Add pcibios hooks for adding and removing PCI buses
PCI: acpiphp: Replace local macros with standard ACPI macros
PCI: acpiphp: Remove all functions even if function 0 doesn't exist
PCI: acpiphp: Use list_for_each_entry_safe() in acpiphp_sanitize_bus()
PCI: Clean up usages of pci_bus->is_added
PCI: When removing bus, always remove legacy files & unregister
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r-- | drivers/pci/hotplug/Kconfig | 7 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 13 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_core.c | 30 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 415 |
4 files changed, 157 insertions, 308 deletions
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 13e9e63a7266..9fcb87f353d4 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig | |||
@@ -52,15 +52,12 @@ config HOTPLUG_PCI_IBM | |||
52 | When in doubt, say N. | 52 | When in doubt, say N. |
53 | 53 | ||
54 | config HOTPLUG_PCI_ACPI | 54 | config HOTPLUG_PCI_ACPI |
55 | tristate "ACPI PCI Hotplug driver" | 55 | bool "ACPI PCI Hotplug driver" |
56 | depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK) | 56 | depends on HOTPLUG_PCI=y && ((!ACPI_DOCK && ACPI) || (ACPI_DOCK)) |
57 | help | 57 | help |
58 | Say Y here if you have a system that supports PCI Hotplug using | 58 | Say Y here if you have a system that supports PCI Hotplug using |
59 | ACPI. | 59 | ACPI. |
60 | 60 | ||
61 | To compile this driver as a module, choose M here: the | ||
62 | module will be called acpiphp. | ||
63 | |||
64 | When in doubt, say N. | 61 | When in doubt, say N. |
65 | 62 | ||
66 | config HOTPLUG_PCI_ACPI_IBM | 63 | config HOTPLUG_PCI_ACPI_IBM |
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index b70ac00a117e..6a319f42b30c 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h | |||
@@ -73,8 +73,9 @@ static inline const char *slot_name(struct slot *slot) | |||
73 | */ | 73 | */ |
74 | struct acpiphp_bridge { | 74 | struct acpiphp_bridge { |
75 | struct list_head list; | 75 | struct list_head list; |
76 | struct list_head slots; | ||
77 | struct kref ref; | ||
76 | acpi_handle handle; | 78 | acpi_handle handle; |
77 | struct acpiphp_slot *slots; | ||
78 | 79 | ||
79 | /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */ | 80 | /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */ |
80 | struct acpiphp_func *func; | 81 | struct acpiphp_func *func; |
@@ -97,7 +98,7 @@ struct acpiphp_bridge { | |||
97 | * PCI slot information for each *physical* PCI slot | 98 | * PCI slot information for each *physical* PCI slot |
98 | */ | 99 | */ |
99 | struct acpiphp_slot { | 100 | struct acpiphp_slot { |
100 | struct acpiphp_slot *next; | 101 | struct list_head node; |
101 | struct acpiphp_bridge *bridge; /* parent */ | 102 | struct acpiphp_bridge *bridge; /* parent */ |
102 | struct list_head funcs; /* one slot may have different | 103 | struct list_head funcs; /* one slot may have different |
103 | objects (i.e. for each function) */ | 104 | objects (i.e. for each function) */ |
@@ -119,7 +120,6 @@ struct acpiphp_slot { | |||
119 | */ | 120 | */ |
120 | struct acpiphp_func { | 121 | struct acpiphp_func { |
121 | struct acpiphp_slot *slot; /* parent */ | 122 | struct acpiphp_slot *slot; /* parent */ |
122 | struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */ | ||
123 | 123 | ||
124 | struct list_head sibling; | 124 | struct list_head sibling; |
125 | struct notifier_block nb; | 125 | struct notifier_block nb; |
@@ -146,10 +146,6 @@ struct acpiphp_attention_info | |||
146 | #define ACPI_PCI_HOST_HID "PNP0A03" | 146 | #define ACPI_PCI_HOST_HID "PNP0A03" |
147 | 147 | ||
148 | /* ACPI _STA method value (ignore bit 4; battery present) */ | 148 | /* ACPI _STA method value (ignore bit 4; battery present) */ |
149 | #define ACPI_STA_PRESENT (0x00000001) | ||
150 | #define ACPI_STA_ENABLED (0x00000002) | ||
151 | #define ACPI_STA_SHOW_IN_UI (0x00000004) | ||
152 | #define ACPI_STA_FUNCTIONING (0x00000008) | ||
153 | #define ACPI_STA_ALL (0x0000000f) | 149 | #define ACPI_STA_ALL (0x0000000f) |
154 | 150 | ||
155 | /* bridge flags */ | 151 | /* bridge flags */ |
@@ -180,8 +176,6 @@ extern int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot); | |||
180 | extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); | 176 | extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); |
181 | 177 | ||
182 | /* acpiphp_glue.c */ | 178 | /* acpiphp_glue.c */ |
183 | extern int acpiphp_glue_init (void); | ||
184 | extern void acpiphp_glue_exit (void); | ||
185 | typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); | 179 | typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); |
186 | 180 | ||
187 | extern int acpiphp_enable_slot (struct acpiphp_slot *slot); | 181 | extern int acpiphp_enable_slot (struct acpiphp_slot *slot); |
@@ -194,5 +188,6 @@ extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); | |||
194 | 188 | ||
195 | /* variables */ | 189 | /* variables */ |
196 | extern bool acpiphp_debug; | 190 | extern bool acpiphp_debug; |
191 | extern bool acpiphp_disabled; | ||
197 | 192 | ||
198 | #endif /* _ACPIPHP_H */ | 193 | #endif /* _ACPIPHP_H */ |
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index c2fd3095701f..ca8127950fcd 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c | |||
@@ -37,6 +37,7 @@ | |||
37 | 37 | ||
38 | #include <linux/kernel.h> | 38 | #include <linux/kernel.h> |
39 | #include <linux/pci.h> | 39 | #include <linux/pci.h> |
40 | #include <linux/pci-acpi.h> | ||
40 | #include <linux/pci_hotplug.h> | 41 | #include <linux/pci_hotplug.h> |
41 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
42 | #include <linux/smp.h> | 43 | #include <linux/smp.h> |
@@ -48,6 +49,7 @@ | |||
48 | #define SLOT_NAME_SIZE 21 /* {_SUN} */ | 49 | #define SLOT_NAME_SIZE 21 /* {_SUN} */ |
49 | 50 | ||
50 | bool acpiphp_debug; | 51 | bool acpiphp_debug; |
52 | bool acpiphp_disabled; | ||
51 | 53 | ||
52 | /* local variables */ | 54 | /* local variables */ |
53 | static struct acpiphp_attention_info *attention_info; | 55 | static struct acpiphp_attention_info *attention_info; |
@@ -60,7 +62,9 @@ MODULE_AUTHOR(DRIVER_AUTHOR); | |||
60 | MODULE_DESCRIPTION(DRIVER_DESC); | 62 | MODULE_DESCRIPTION(DRIVER_DESC); |
61 | MODULE_LICENSE("GPL"); | 63 | MODULE_LICENSE("GPL"); |
62 | MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); | 64 | MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); |
65 | MODULE_PARM_DESC(disable, "disable acpiphp driver"); | ||
63 | module_param_named(debug, acpiphp_debug, bool, 0644); | 66 | module_param_named(debug, acpiphp_debug, bool, 0644); |
67 | module_param_named(disable, acpiphp_disabled, bool, 0444); | ||
64 | 68 | ||
65 | /* export the attention callback registration methods */ | 69 | /* export the attention callback registration methods */ |
66 | EXPORT_SYMBOL_GPL(acpiphp_register_attention); | 70 | EXPORT_SYMBOL_GPL(acpiphp_register_attention); |
@@ -351,27 +355,9 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot) | |||
351 | } | 355 | } |
352 | 356 | ||
353 | 357 | ||
354 | static int __init acpiphp_init(void) | 358 | void __init acpiphp_init(void) |
355 | { | 359 | { |
356 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 360 | info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n", |
357 | 361 | acpiphp_disabled ? ", disabled by user; please report a bug" | |
358 | if (acpi_pci_disabled) | 362 | : ""); |
359 | return 0; | ||
360 | |||
361 | /* read all the ACPI info from the system */ | ||
362 | /* initialize internal data structure etc. */ | ||
363 | return acpiphp_glue_init(); | ||
364 | } | ||
365 | |||
366 | |||
367 | static void __exit acpiphp_exit(void) | ||
368 | { | ||
369 | if (acpi_pci_disabled) | ||
370 | return; | ||
371 | |||
372 | /* deallocate internal data structures etc. */ | ||
373 | acpiphp_glue_exit(); | ||
374 | } | 363 | } |
375 | |||
376 | module_init(acpiphp_init); | ||
377 | module_exit(acpiphp_exit); | ||
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 270fdbadc19c..96fed19c6d90 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include "acpiphp.h" | 54 | #include "acpiphp.h" |
55 | 55 | ||
56 | static LIST_HEAD(bridge_list); | 56 | static LIST_HEAD(bridge_list); |
57 | static DEFINE_MUTEX(bridge_mutex); | ||
57 | 58 | ||
58 | #define MY_NAME "acpiphp_glue" | 59 | #define MY_NAME "acpiphp_glue" |
59 | 60 | ||
@@ -61,6 +62,7 @@ static void handle_hotplug_event_bridge (acpi_handle, u32, void *); | |||
61 | static void acpiphp_sanitize_bus(struct pci_bus *bus); | 62 | static void acpiphp_sanitize_bus(struct pci_bus *bus); |
62 | static void acpiphp_set_hpp_values(struct pci_bus *bus); | 63 | static void acpiphp_set_hpp_values(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); |
65 | static void free_bridge(struct kref *kref); | ||
64 | 66 | ||
65 | /* callback routine to check for the existence of a pci dock device */ | 67 | /* callback routine to check for the existence of a pci dock device */ |
66 | static acpi_status | 68 | static acpi_status |
@@ -76,6 +78,39 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
76 | } | 78 | } |
77 | } | 79 | } |
78 | 80 | ||
81 | static inline void get_bridge(struct acpiphp_bridge *bridge) | ||
82 | { | ||
83 | kref_get(&bridge->ref); | ||
84 | } | ||
85 | |||
86 | static inline void put_bridge(struct acpiphp_bridge *bridge) | ||
87 | { | ||
88 | kref_put(&bridge->ref, free_bridge); | ||
89 | } | ||
90 | |||
91 | static void free_bridge(struct kref *kref) | ||
92 | { | ||
93 | struct acpiphp_bridge *bridge; | ||
94 | struct acpiphp_slot *slot, *next; | ||
95 | struct acpiphp_func *func, *tmp; | ||
96 | |||
97 | bridge = container_of(kref, struct acpiphp_bridge, ref); | ||
98 | |||
99 | list_for_each_entry_safe(slot, next, &bridge->slots, node) { | ||
100 | list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) { | ||
101 | kfree(func); | ||
102 | } | ||
103 | kfree(slot); | ||
104 | } | ||
105 | |||
106 | /* Release reference acquired by acpiphp_bridge_handle_to_function() */ | ||
107 | if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) | ||
108 | put_bridge(bridge->func->slot->bridge); | ||
109 | put_device(&bridge->pci_bus->dev); | ||
110 | pci_dev_put(bridge->pci_dev); | ||
111 | kfree(bridge); | ||
112 | } | ||
113 | |||
79 | /* | 114 | /* |
80 | * the _DCK method can do funny things... and sometimes not | 115 | * the _DCK method can do funny things... and sometimes not |
81 | * hah-hah funny. | 116 | * hah-hah funny. |
@@ -154,9 +189,10 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
154 | acpi_handle tmp; | 189 | acpi_handle tmp; |
155 | acpi_status status = AE_OK; | 190 | acpi_status status = AE_OK; |
156 | unsigned long long adr, sun; | 191 | unsigned long long adr, sun; |
157 | int device, function, retval; | 192 | int device, function, retval, found = 0; |
158 | struct pci_bus *pbus = bridge->pci_bus; | 193 | struct pci_bus *pbus = bridge->pci_bus; |
159 | struct pci_dev *pdev; | 194 | struct pci_dev *pdev; |
195 | u32 val; | ||
160 | 196 | ||
161 | if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) | 197 | if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) |
162 | return AE_OK; | 198 | return AE_OK; |
@@ -170,7 +206,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
170 | device = (adr >> 16) & 0xffff; | 206 | device = (adr >> 16) & 0xffff; |
171 | function = adr & 0xffff; | 207 | function = adr & 0xffff; |
172 | 208 | ||
173 | pdev = pbus->self; | 209 | pdev = bridge->pci_dev; |
174 | if (pdev && device_is_managed_by_native_pciehp(pdev)) | 210 | if (pdev && device_is_managed_by_native_pciehp(pdev)) |
175 | return AE_OK; | 211 | return AE_OK; |
176 | 212 | ||
@@ -178,7 +214,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
178 | if (!newfunc) | 214 | if (!newfunc) |
179 | return AE_NO_MEMORY; | 215 | return AE_NO_MEMORY; |
180 | 216 | ||
181 | INIT_LIST_HEAD(&newfunc->sibling); | ||
182 | newfunc->handle = handle; | 217 | newfunc->handle = handle; |
183 | newfunc->function = function; | 218 | newfunc->function = function; |
184 | 219 | ||
@@ -207,14 +242,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
207 | } | 242 | } |
208 | 243 | ||
209 | /* search for objects that share the same slot */ | 244 | /* search for objects that share the same slot */ |
210 | for (slot = bridge->slots; slot; slot = slot->next) | 245 | list_for_each_entry(slot, &bridge->slots, node) |
211 | if (slot->device == device) { | 246 | if (slot->device == device) { |
212 | if (slot->sun != sun) | 247 | if (slot->sun != sun) |
213 | warn("sibling found, but _SUN doesn't match!\n"); | 248 | warn("sibling found, but _SUN doesn't match!\n"); |
249 | found = 1; | ||
214 | break; | 250 | break; |
215 | } | 251 | } |
216 | 252 | ||
217 | if (!slot) { | 253 | if (!found) { |
218 | slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); | 254 | slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); |
219 | if (!slot) { | 255 | if (!slot) { |
220 | kfree(newfunc); | 256 | kfree(newfunc); |
@@ -227,9 +263,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
227 | INIT_LIST_HEAD(&slot->funcs); | 263 | INIT_LIST_HEAD(&slot->funcs); |
228 | mutex_init(&slot->crit_sect); | 264 | mutex_init(&slot->crit_sect); |
229 | 265 | ||
230 | slot->next = bridge->slots; | 266 | mutex_lock(&bridge_mutex); |
231 | bridge->slots = slot; | 267 | list_add_tail(&slot->node, &bridge->slots); |
232 | 268 | mutex_unlock(&bridge_mutex); | |
233 | bridge->nr_slots++; | 269 | bridge->nr_slots++; |
234 | 270 | ||
235 | dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", | 271 | dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", |
@@ -247,13 +283,13 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
247 | } | 283 | } |
248 | 284 | ||
249 | newfunc->slot = slot; | 285 | newfunc->slot = slot; |
286 | mutex_lock(&bridge_mutex); | ||
250 | list_add_tail(&newfunc->sibling, &slot->funcs); | 287 | list_add_tail(&newfunc->sibling, &slot->funcs); |
288 | mutex_unlock(&bridge_mutex); | ||
251 | 289 | ||
252 | pdev = pci_get_slot(pbus, PCI_DEVFN(device, function)); | 290 | if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function), |
253 | if (pdev) { | 291 | &val, 60*1000)) |
254 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); | 292 | slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); |
255 | pci_dev_put(pdev); | ||
256 | } | ||
257 | 293 | ||
258 | if (is_dock_device(handle)) { | 294 | if (is_dock_device(handle)) { |
259 | /* we don't want to call this device's _EJ0 | 295 | /* we don't want to call this device's _EJ0 |
@@ -290,7 +326,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
290 | 326 | ||
291 | err_exit: | 327 | err_exit: |
292 | bridge->nr_slots--; | 328 | bridge->nr_slots--; |
293 | bridge->slots = slot->next; | 329 | mutex_lock(&bridge_mutex); |
330 | list_del(&slot->node); | ||
331 | mutex_unlock(&bridge_mutex); | ||
294 | kfree(slot); | 332 | kfree(slot); |
295 | kfree(newfunc); | 333 | kfree(newfunc); |
296 | 334 | ||
@@ -315,13 +353,17 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) | |||
315 | acpi_status status; | 353 | acpi_status status; |
316 | 354 | ||
317 | /* must be added to the list prior to calling register_slot */ | 355 | /* must be added to the list prior to calling register_slot */ |
356 | mutex_lock(&bridge_mutex); | ||
318 | list_add(&bridge->list, &bridge_list); | 357 | list_add(&bridge->list, &bridge_list); |
358 | mutex_unlock(&bridge_mutex); | ||
319 | 359 | ||
320 | /* register all slot objects under this bridge */ | 360 | /* register all slot objects under this bridge */ |
321 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, | 361 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, |
322 | register_slot, NULL, bridge, NULL); | 362 | register_slot, NULL, bridge, NULL); |
323 | if (ACPI_FAILURE(status)) { | 363 | if (ACPI_FAILURE(status)) { |
364 | mutex_lock(&bridge_mutex); | ||
324 | list_del(&bridge->list); | 365 | list_del(&bridge->list); |
366 | mutex_unlock(&bridge_mutex); | ||
325 | return; | 367 | return; |
326 | } | 368 | } |
327 | 369 | ||
@@ -351,178 +393,46 @@ static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle | |||
351 | { | 393 | { |
352 | struct acpiphp_bridge *bridge; | 394 | struct acpiphp_bridge *bridge; |
353 | struct acpiphp_slot *slot; | 395 | struct acpiphp_slot *slot; |
354 | struct acpiphp_func *func; | 396 | struct acpiphp_func *func = NULL; |
355 | 397 | ||
398 | mutex_lock(&bridge_mutex); | ||
356 | list_for_each_entry(bridge, &bridge_list, list) { | 399 | list_for_each_entry(bridge, &bridge_list, list) { |
357 | for (slot = bridge->slots; slot; slot = slot->next) { | 400 | list_for_each_entry(slot, &bridge->slots, node) { |
358 | list_for_each_entry(func, &slot->funcs, sibling) { | 401 | list_for_each_entry(func, &slot->funcs, sibling) { |
359 | if (func->handle == handle) | 402 | if (func->handle == handle) { |
403 | get_bridge(func->slot->bridge); | ||
404 | mutex_unlock(&bridge_mutex); | ||
360 | return func; | 405 | return func; |
406 | } | ||
361 | } | 407 | } |
362 | } | 408 | } |
363 | } | 409 | } |
410 | mutex_unlock(&bridge_mutex); | ||
364 | 411 | ||
365 | return NULL; | 412 | return NULL; |
366 | } | 413 | } |
367 | 414 | ||
368 | 415 | ||
369 | static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) | ||
370 | { | ||
371 | acpi_handle dummy_handle; | ||
372 | struct acpiphp_func *func; | ||
373 | |||
374 | if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
375 | "_EJ0", &dummy_handle))) { | ||
376 | bridge->flags |= BRIDGE_HAS_EJ0; | ||
377 | |||
378 | dbg("found ejectable p2p bridge\n"); | ||
379 | |||
380 | /* make link between PCI bridge and PCI function */ | ||
381 | func = acpiphp_bridge_handle_to_function(bridge->handle); | ||
382 | if (!func) | ||
383 | return; | ||
384 | bridge->func = func; | ||
385 | func->bridge = bridge; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | |||
390 | /* allocate and initialize host bridge data structure */ | ||
391 | static void add_host_bridge(struct acpi_pci_root *root) | ||
392 | { | ||
393 | struct acpiphp_bridge *bridge; | ||
394 | acpi_handle handle = root->device->handle; | ||
395 | |||
396 | bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); | ||
397 | if (bridge == NULL) | ||
398 | return; | ||
399 | |||
400 | bridge->handle = handle; | ||
401 | |||
402 | bridge->pci_bus = root->bus; | ||
403 | |||
404 | init_bridge_misc(bridge); | ||
405 | } | ||
406 | |||
407 | |||
408 | /* allocate and initialize PCI-to-PCI bridge data structure */ | ||
409 | static void add_p2p_bridge(acpi_handle *handle) | ||
410 | { | ||
411 | struct acpiphp_bridge *bridge; | ||
412 | |||
413 | bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); | ||
414 | if (bridge == NULL) { | ||
415 | err("out of memory\n"); | ||
416 | return; | ||
417 | } | ||
418 | |||
419 | bridge->handle = handle; | ||
420 | config_p2p_bridge_flags(bridge); | ||
421 | |||
422 | bridge->pci_dev = acpi_get_pci_dev(handle); | ||
423 | bridge->pci_bus = bridge->pci_dev->subordinate; | ||
424 | if (!bridge->pci_bus) { | ||
425 | err("This is not a PCI-to-PCI bridge!\n"); | ||
426 | goto err; | ||
427 | } | ||
428 | |||
429 | /* | ||
430 | * Grab a ref to the subordinate PCI bus in case the bus is | ||
431 | * removed via PCI core logical hotplug. The ref pins the bus | ||
432 | * (which we access during module unload). | ||
433 | */ | ||
434 | get_device(&bridge->pci_bus->dev); | ||
435 | |||
436 | init_bridge_misc(bridge); | ||
437 | return; | ||
438 | err: | ||
439 | pci_dev_put(bridge->pci_dev); | ||
440 | kfree(bridge); | ||
441 | return; | ||
442 | } | ||
443 | |||
444 | |||
445 | /* callback routine to find P2P bridges */ | ||
446 | static acpi_status | ||
447 | find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
448 | { | ||
449 | acpi_status status; | ||
450 | struct pci_dev *dev; | ||
451 | |||
452 | dev = acpi_get_pci_dev(handle); | ||
453 | if (!dev || !dev->subordinate) | ||
454 | goto out; | ||
455 | |||
456 | /* check if this bridge has ejectable slots */ | ||
457 | if ((detect_ejectable_slots(handle) > 0)) { | ||
458 | dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); | ||
459 | add_p2p_bridge(handle); | ||
460 | } | ||
461 | |||
462 | /* search P2P bridges under this p2p bridge */ | ||
463 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | ||
464 | find_p2p_bridge, NULL, NULL, NULL); | ||
465 | if (ACPI_FAILURE(status)) | ||
466 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); | ||
467 | |||
468 | out: | ||
469 | pci_dev_put(dev); | ||
470 | return AE_OK; | ||
471 | } | ||
472 | |||
473 | |||
474 | /* find hot-pluggable slots, and then find P2P bridge */ | ||
475 | static int add_bridge(struct acpi_pci_root *root) | ||
476 | { | ||
477 | acpi_status status; | ||
478 | unsigned long long tmp; | ||
479 | acpi_handle dummy_handle; | ||
480 | acpi_handle handle = root->device->handle; | ||
481 | |||
482 | /* if the bridge doesn't have _STA, we assume it is always there */ | ||
483 | status = acpi_get_handle(handle, "_STA", &dummy_handle); | ||
484 | if (ACPI_SUCCESS(status)) { | ||
485 | status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); | ||
486 | if (ACPI_FAILURE(status)) { | ||
487 | dbg("%s: _STA evaluation failure\n", __func__); | ||
488 | return 0; | ||
489 | } | ||
490 | if ((tmp & ACPI_STA_FUNCTIONING) == 0) | ||
491 | /* don't register this object */ | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | /* check if this bridge has ejectable slots */ | ||
496 | if (detect_ejectable_slots(handle) > 0) { | ||
497 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); | ||
498 | add_host_bridge(root); | ||
499 | } | ||
500 | |||
501 | /* search P2P bridges under this host bridge */ | ||
502 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | ||
503 | find_p2p_bridge, NULL, NULL, NULL); | ||
504 | |||
505 | if (ACPI_FAILURE(status)) | ||
506 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) | 416 | static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) |
512 | { | 417 | { |
513 | struct acpiphp_bridge *bridge; | 418 | struct acpiphp_bridge *bridge; |
514 | 419 | ||
420 | mutex_lock(&bridge_mutex); | ||
515 | list_for_each_entry(bridge, &bridge_list, list) | 421 | list_for_each_entry(bridge, &bridge_list, list) |
516 | if (bridge->handle == handle) | 422 | if (bridge->handle == handle) { |
423 | get_bridge(bridge); | ||
424 | mutex_unlock(&bridge_mutex); | ||
517 | return bridge; | 425 | return bridge; |
426 | } | ||
427 | mutex_unlock(&bridge_mutex); | ||
518 | 428 | ||
519 | return NULL; | 429 | return NULL; |
520 | } | 430 | } |
521 | 431 | ||
522 | static void cleanup_bridge(struct acpiphp_bridge *bridge) | 432 | static void cleanup_bridge(struct acpiphp_bridge *bridge) |
523 | { | 433 | { |
524 | struct acpiphp_slot *slot, *next; | 434 | struct acpiphp_slot *slot; |
525 | struct acpiphp_func *func, *tmp; | 435 | struct acpiphp_func *func; |
526 | acpi_status status; | 436 | acpi_status status; |
527 | acpi_handle handle = bridge->handle; | 437 | acpi_handle handle = bridge->handle; |
528 | 438 | ||
@@ -543,10 +453,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
543 | err("failed to install interrupt notify handler\n"); | 453 | err("failed to install interrupt notify handler\n"); |
544 | } | 454 | } |
545 | 455 | ||
546 | slot = bridge->slots; | 456 | list_for_each_entry(slot, &bridge->slots, node) { |
547 | while (slot) { | 457 | list_for_each_entry(func, &slot->funcs, sibling) { |
548 | next = slot->next; | ||
549 | list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) { | ||
550 | if (is_dock_device(func->handle)) { | 458 | if (is_dock_device(func->handle)) { |
551 | unregister_hotplug_dock_device(func->handle); | 459 | unregister_hotplug_dock_device(func->handle); |
552 | unregister_dock_notifier(&func->nb); | 460 | unregister_dock_notifier(&func->nb); |
@@ -558,63 +466,13 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
558 | if (ACPI_FAILURE(status)) | 466 | if (ACPI_FAILURE(status)) |
559 | err("failed to remove notify handler\n"); | 467 | err("failed to remove notify handler\n"); |
560 | } | 468 | } |
561 | list_del(&func->sibling); | ||
562 | kfree(func); | ||
563 | } | 469 | } |
564 | acpiphp_unregister_hotplug_slot(slot); | 470 | acpiphp_unregister_hotplug_slot(slot); |
565 | list_del(&slot->funcs); | ||
566 | kfree(slot); | ||
567 | slot = next; | ||
568 | } | 471 | } |
569 | 472 | ||
570 | /* | 473 | mutex_lock(&bridge_mutex); |
571 | * Only P2P bridges have a pci_dev | ||
572 | */ | ||
573 | if (bridge->pci_dev) | ||
574 | put_device(&bridge->pci_bus->dev); | ||
575 | |||
576 | pci_dev_put(bridge->pci_dev); | ||
577 | list_del(&bridge->list); | 474 | list_del(&bridge->list); |
578 | kfree(bridge); | 475 | mutex_unlock(&bridge_mutex); |
579 | } | ||
580 | |||
581 | static acpi_status | ||
582 | cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
583 | { | ||
584 | struct acpiphp_bridge *bridge; | ||
585 | |||
586 | /* cleanup p2p bridges under this P2P bridge | ||
587 | in a depth-first manner */ | ||
588 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | ||
589 | cleanup_p2p_bridge, NULL, NULL, NULL); | ||
590 | |||
591 | bridge = acpiphp_handle_to_bridge(handle); | ||
592 | if (bridge) | ||
593 | cleanup_bridge(bridge); | ||
594 | |||
595 | return AE_OK; | ||
596 | } | ||
597 | |||
598 | static void remove_bridge(struct acpi_pci_root *root) | ||
599 | { | ||
600 | struct acpiphp_bridge *bridge; | ||
601 | acpi_handle handle = root->device->handle; | ||
602 | |||
603 | /* cleanup p2p bridges under this host bridge | ||
604 | in a depth-first manner */ | ||
605 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, | ||
606 | (u32)1, cleanup_p2p_bridge, NULL, NULL, NULL); | ||
607 | |||
608 | /* | ||
609 | * On root bridges with hotplug slots directly underneath (ie, | ||
610 | * no p2p bridge between), we call cleanup_bridge(). | ||
611 | * | ||
612 | * The else clause cleans up root bridges that either had no | ||
613 | * hotplug slots at all, or had a p2p bridge underneath. | ||
614 | */ | ||
615 | bridge = acpiphp_handle_to_bridge(handle); | ||
616 | if (bridge) | ||
617 | cleanup_bridge(bridge); | ||
618 | } | 476 | } |
619 | 477 | ||
620 | static int power_on_slot(struct acpiphp_slot *slot) | 478 | static int power_on_slot(struct acpiphp_slot *slot) |
@@ -798,6 +656,7 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) | |||
798 | } | 656 | } |
799 | } | 657 | } |
800 | } | 658 | } |
659 | |||
801 | /** | 660 | /** |
802 | * enable_device - enable, configure a slot | 661 | * enable_device - enable, configure a slot |
803 | * @slot: slot to be enabled | 662 | * @slot: slot to be enabled |
@@ -810,9 +669,7 @@ static int __ref enable_device(struct acpiphp_slot *slot) | |||
810 | struct pci_dev *dev; | 669 | struct pci_dev *dev; |
811 | struct pci_bus *bus = slot->bridge->pci_bus; | 670 | struct pci_bus *bus = slot->bridge->pci_bus; |
812 | struct acpiphp_func *func; | 671 | struct acpiphp_func *func; |
813 | int retval = 0; | ||
814 | int num, max, pass; | 672 | int num, max, pass; |
815 | acpi_status status; | ||
816 | 673 | ||
817 | if (slot->flags & SLOT_ENABLED) | 674 | if (slot->flags & SLOT_ENABLED) |
818 | goto err_exit; | 675 | goto err_exit; |
@@ -867,23 +724,11 @@ static int __ref enable_device(struct acpiphp_slot *slot) | |||
867 | slot->flags &= (~SLOT_ENABLED); | 724 | slot->flags &= (~SLOT_ENABLED); |
868 | continue; | 725 | continue; |
869 | } | 726 | } |
870 | |||
871 | if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE && | ||
872 | dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) { | ||
873 | pci_dev_put(dev); | ||
874 | continue; | ||
875 | } | ||
876 | |||
877 | status = find_p2p_bridge(func->handle, (u32)1, bus, NULL); | ||
878 | if (ACPI_FAILURE(status)) | ||
879 | warn("find_p2p_bridge failed (error code = 0x%x)\n", | ||
880 | status); | ||
881 | pci_dev_put(dev); | ||
882 | } | 727 | } |
883 | 728 | ||
884 | 729 | ||
885 | err_exit: | 730 | err_exit: |
886 | return retval; | 731 | return 0; |
887 | } | 732 | } |
888 | 733 | ||
889 | /* return first device in slot, acquiring a reference on it */ | 734 | /* return first device in slot, acquiring a reference on it */ |
@@ -912,23 +757,6 @@ static int disable_device(struct acpiphp_slot *slot) | |||
912 | { | 757 | { |
913 | struct acpiphp_func *func; | 758 | struct acpiphp_func *func; |
914 | struct pci_dev *pdev; | 759 | struct pci_dev *pdev; |
915 | struct pci_bus *bus = slot->bridge->pci_bus; | ||
916 | |||
917 | /* The slot will be enabled when func 0 is added, so check | ||
918 | func 0 before disable the slot. */ | ||
919 | pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0)); | ||
920 | if (!pdev) | ||
921 | goto err_exit; | ||
922 | pci_dev_put(pdev); | ||
923 | |||
924 | list_for_each_entry(func, &slot->funcs, sibling) { | ||
925 | if (func->bridge) { | ||
926 | /* cleanup p2p bridges under this P2P bridge */ | ||
927 | cleanup_p2p_bridge(func->bridge->handle, | ||
928 | (u32)1, NULL, NULL); | ||
929 | func->bridge = NULL; | ||
930 | } | ||
931 | } | ||
932 | 760 | ||
933 | /* | 761 | /* |
934 | * enable_device() enumerates all functions in this device via | 762 | * enable_device() enumerates all functions in this device via |
@@ -947,7 +775,6 @@ static int disable_device(struct acpiphp_slot *slot) | |||
947 | 775 | ||
948 | slot->flags &= (~SLOT_ENABLED); | 776 | slot->flags &= (~SLOT_ENABLED); |
949 | 777 | ||
950 | err_exit: | ||
951 | return 0; | 778 | return 0; |
952 | } | 779 | } |
953 | 780 | ||
@@ -1037,7 +864,7 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) | |||
1037 | 864 | ||
1038 | enabled = disabled = 0; | 865 | enabled = disabled = 0; |
1039 | 866 | ||
1040 | for (slot = bridge->slots; slot; slot = slot->next) { | 867 | list_for_each_entry(slot, &bridge->slots, node) { |
1041 | unsigned int status = get_slot_status(slot); | 868 | unsigned int status = get_slot_status(slot); |
1042 | if (slot->flags & SLOT_ENABLED) { | 869 | if (slot->flags & SLOT_ENABLED) { |
1043 | if (status == ACPI_STA_ALL) | 870 | if (status == ACPI_STA_ALL) |
@@ -1082,11 +909,11 @@ static void acpiphp_set_hpp_values(struct pci_bus *bus) | |||
1082 | */ | 909 | */ |
1083 | static void acpiphp_sanitize_bus(struct pci_bus *bus) | 910 | static void acpiphp_sanitize_bus(struct pci_bus *bus) |
1084 | { | 911 | { |
1085 | struct pci_dev *dev; | 912 | struct pci_dev *dev, *tmp; |
1086 | int i; | 913 | int i; |
1087 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; | 914 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; |
1088 | 915 | ||
1089 | list_for_each_entry(dev, &bus->devices, bus_list) { | 916 | list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { |
1090 | for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { | 917 | for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { |
1091 | struct resource *res = &dev->resource[i]; | 918 | struct resource *res = &dev->resource[i]; |
1092 | if ((res->flags & type_mask) && !res->start && | 919 | if ((res->flags & type_mask) && !res->start && |
@@ -1118,6 +945,7 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
1118 | dbg("%s: re-enumerating slots under %s\n", | 945 | dbg("%s: re-enumerating slots under %s\n", |
1119 | __func__, objname); | 946 | __func__, objname); |
1120 | acpiphp_check_bridge(bridge); | 947 | acpiphp_check_bridge(bridge); |
948 | put_bridge(bridge); | ||
1121 | } | 949 | } |
1122 | return AE_OK ; | 950 | return AE_OK ; |
1123 | } | 951 | } |
@@ -1195,6 +1023,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) | |||
1195 | 1023 | ||
1196 | acpi_scan_lock_release(); | 1024 | acpi_scan_lock_release(); |
1197 | kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ | 1025 | kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ |
1026 | put_bridge(bridge); | ||
1198 | } | 1027 | } |
1199 | 1028 | ||
1200 | /** | 1029 | /** |
@@ -1208,6 +1037,8 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) | |||
1208 | static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, | 1037 | static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, |
1209 | void *context) | 1038 | void *context) |
1210 | { | 1039 | { |
1040 | struct acpiphp_bridge *bridge = context; | ||
1041 | |||
1211 | /* | 1042 | /* |
1212 | * Currently the code adds all hotplug events to the kacpid_wq | 1043 | * Currently the code adds all hotplug events to the kacpid_wq |
1213 | * queue when it should add hotplug events to the kacpi_hotplug_wq. | 1044 | * queue when it should add hotplug events to the kacpi_hotplug_wq. |
@@ -1216,6 +1047,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, | |||
1216 | * For now just re-add this work to the kacpi_hotplug_wq so we | 1047 | * For now just re-add this work to the kacpi_hotplug_wq so we |
1217 | * don't deadlock on hotplug actions. | 1048 | * don't deadlock on hotplug actions. |
1218 | */ | 1049 | */ |
1050 | get_bridge(bridge); | ||
1219 | alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge); | 1051 | alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge); |
1220 | } | 1052 | } |
1221 | 1053 | ||
@@ -1270,6 +1102,7 @@ static void _handle_hotplug_event_func(struct work_struct *work) | |||
1270 | 1102 | ||
1271 | acpi_scan_lock_release(); | 1103 | acpi_scan_lock_release(); |
1272 | kfree(hp_work); /* allocated in handle_hotplug_event_func */ | 1104 | kfree(hp_work); /* allocated in handle_hotplug_event_func */ |
1105 | put_bridge(func->slot->bridge); | ||
1273 | } | 1106 | } |
1274 | 1107 | ||
1275 | /** | 1108 | /** |
@@ -1283,6 +1116,8 @@ static void _handle_hotplug_event_func(struct work_struct *work) | |||
1283 | static void handle_hotplug_event_func(acpi_handle handle, u32 type, | 1116 | static void handle_hotplug_event_func(acpi_handle handle, u32 type, |
1284 | void *context) | 1117 | void *context) |
1285 | { | 1118 | { |
1119 | struct acpiphp_func *func = context; | ||
1120 | |||
1286 | /* | 1121 | /* |
1287 | * Currently the code adds all hotplug events to the kacpid_wq | 1122 | * Currently the code adds all hotplug events to the kacpid_wq |
1288 | * queue when it should add hotplug events to the kacpi_hotplug_wq. | 1123 | * queue when it should add hotplug events to the kacpi_hotplug_wq. |
@@ -1291,33 +1126,69 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, | |||
1291 | * For now just re-add this work to the kacpi_hotplug_wq so we | 1126 | * For now just re-add this work to the kacpi_hotplug_wq so we |
1292 | * don't deadlock on hotplug actions. | 1127 | * don't deadlock on hotplug actions. |
1293 | */ | 1128 | */ |
1129 | get_bridge(func->slot->bridge); | ||
1294 | alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func); | 1130 | alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func); |
1295 | } | 1131 | } |
1296 | 1132 | ||
1297 | static struct acpi_pci_driver acpi_pci_hp_driver = { | 1133 | /* |
1298 | .add = add_bridge, | 1134 | * Create hotplug slots for the PCI bus. |
1299 | .remove = remove_bridge, | 1135 | * It should always return 0 to avoid skipping following notifiers. |
1300 | }; | ||
1301 | |||
1302 | /** | ||
1303 | * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures | ||
1304 | */ | 1136 | */ |
1305 | int __init acpiphp_glue_init(void) | 1137 | void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle) |
1306 | { | 1138 | { |
1307 | acpi_pci_register_driver(&acpi_pci_hp_driver); | 1139 | acpi_handle dummy_handle; |
1140 | struct acpiphp_bridge *bridge; | ||
1308 | 1141 | ||
1309 | return 0; | 1142 | if (acpiphp_disabled) |
1310 | } | 1143 | return; |
1311 | 1144 | ||
1145 | if (detect_ejectable_slots(handle) <= 0) | ||
1146 | return; | ||
1312 | 1147 | ||
1313 | /** | 1148 | bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); |
1314 | * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures | 1149 | if (bridge == NULL) { |
1315 | * | 1150 | err("out of memory\n"); |
1316 | * This function frees all data allocated in acpiphp_glue_init(). | 1151 | return; |
1317 | */ | 1152 | } |
1318 | void acpiphp_glue_exit(void) | 1153 | |
1154 | INIT_LIST_HEAD(&bridge->slots); | ||
1155 | kref_init(&bridge->ref); | ||
1156 | bridge->handle = handle; | ||
1157 | bridge->pci_dev = pci_dev_get(bus->self); | ||
1158 | bridge->pci_bus = bus; | ||
1159 | |||
1160 | /* | ||
1161 | * Grab a ref to the subordinate PCI bus in case the bus is | ||
1162 | * removed via PCI core logical hotplug. The ref pins the bus | ||
1163 | * (which we access during module unload). | ||
1164 | */ | ||
1165 | get_device(&bus->dev); | ||
1166 | |||
1167 | if (!pci_is_root_bus(bridge->pci_bus) && | ||
1168 | ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
1169 | "_EJ0", &dummy_handle))) { | ||
1170 | dbg("found ejectable p2p bridge\n"); | ||
1171 | bridge->flags |= BRIDGE_HAS_EJ0; | ||
1172 | bridge->func = acpiphp_bridge_handle_to_function(handle); | ||
1173 | } | ||
1174 | |||
1175 | init_bridge_misc(bridge); | ||
1176 | } | ||
1177 | |||
1178 | /* Destroy hotplug slots associated with the PCI bus */ | ||
1179 | void acpiphp_remove_slots(struct pci_bus *bus) | ||
1319 | { | 1180 | { |
1320 | acpi_pci_unregister_driver(&acpi_pci_hp_driver); | 1181 | struct acpiphp_bridge *bridge, *tmp; |
1182 | |||
1183 | if (acpiphp_disabled) | ||
1184 | return; | ||
1185 | |||
1186 | list_for_each_entry_safe(bridge, tmp, &bridge_list, list) | ||
1187 | if (bridge->pci_bus == bus) { | ||
1188 | cleanup_bridge(bridge); | ||
1189 | put_bridge(bridge); | ||
1190 | break; | ||
1191 | } | ||
1321 | } | 1192 | } |
1322 | 1193 | ||
1323 | /** | 1194 | /** |
@@ -1396,7 +1267,7 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot) | |||
1396 | 1267 | ||
1397 | sta = get_slot_status(slot); | 1268 | sta = get_slot_status(slot); |
1398 | 1269 | ||
1399 | return (sta & ACPI_STA_SHOW_IN_UI) ? 0 : 1; | 1270 | return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1; |
1400 | } | 1271 | } |
1401 | 1272 | ||
1402 | 1273 | ||