Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * ACPI PCI HotPlug glue functions to ACPI CA subsystem | |
3 | * | |
4 | * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) | |
5 | * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) | |
6 | * Copyright (C) 2002,2003 NEC Corporation | |
42f49a6a RS |
7 | * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) |
8 | * Copyright (C) 2003-2005 Hewlett Packard | |
8e7561cf RS |
9 | * Copyright (C) 2005 Rajesh Shah (rajesh.shah@intel.com) |
10 | * Copyright (C) 2005 Intel Corporation | |
1da177e4 LT |
11 | * |
12 | * All rights reserved. | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify | |
15 | * it under the terms of the GNU General Public License as published by | |
16 | * the Free Software Foundation; either version 2 of the License, or (at | |
17 | * your option) any later version. | |
18 | * | |
19 | * This program is distributed in the hope that it will be useful, but | |
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | |
22 | * NON INFRINGEMENT. See the GNU General Public License for more | |
23 | * details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public License | |
26 | * along with this program; if not, write to the Free Software | |
27 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
28 | * | |
998be20f | 29 | * Send feedback to <kristen.c.accardi@intel.com> |
1da177e4 LT |
30 | * |
31 | */ | |
32 | ||
42f49a6a RS |
33 | /* |
34 | * Lifetime rules for pci_dev: | |
42f49a6a RS |
35 | * - The one in acpiphp_bridge has its refcount elevated by pci_get_slot() |
36 | * when the bridge is scanned and it loses a refcount when the bridge | |
37 | * is removed. | |
5d4a4b25 AC |
38 | * - When a P2P bridge is present, we elevate the refcount on the subordinate |
39 | * bus. It loses the refcount when the the driver unloads. | |
42f49a6a RS |
40 | */ |
41 | ||
bd950799 LT |
42 | #define pr_fmt(fmt) "acpiphp_glue: " fmt |
43 | ||
1da177e4 LT |
44 | #include <linux/init.h> |
45 | #include <linux/module.h> | |
46 | ||
47 | #include <linux/kernel.h> | |
48 | #include <linux/pci.h> | |
7a54f25c | 49 | #include <linux/pci_hotplug.h> |
e8c331e9 | 50 | #include <linux/pci-acpi.h> |
4ebe3450 | 51 | #include <linux/pm_runtime.h> |
6aa4cdd0 | 52 | #include <linux/mutex.h> |
5a0e3ad6 | 53 | #include <linux/slab.h> |
6af8bef1 | 54 | #include <linux/acpi.h> |
1da177e4 LT |
55 | |
56 | #include "../pci.h" | |
1da177e4 LT |
57 | #include "acpiphp.h" |
58 | ||
59 | static LIST_HEAD(bridge_list); | |
3d54a316 | 60 | static DEFINE_MUTEX(bridge_mutex); |
cb7b8ced | 61 | static DEFINE_MUTEX(acpiphp_context_lock); |
1da177e4 | 62 | |
87831273 | 63 | static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); |
8e5dce35 | 64 | static void acpiphp_sanitize_bus(struct pci_bus *bus); |
fca6825a | 65 | static void acpiphp_set_hpp_values(struct pci_bus *bus); |
43e5c091 | 66 | static void hotplug_event(acpi_handle handle, u32 type, void *data); |
3d54a316 | 67 | static void free_bridge(struct kref *kref); |
8e5dce35 | 68 | |
cb7b8ced RW |
69 | static void acpiphp_context_handler(acpi_handle handle, void *context) |
70 | { | |
71 | /* Intentionally empty. */ | |
72 | } | |
73 | ||
74 | /** | |
75 | * acpiphp_init_context - Create hotplug context and grab a reference to it. | |
76 | * @handle: ACPI object handle to create the context for. | |
77 | * | |
78 | * Call under acpiphp_context_lock. | |
79 | */ | |
80 | static struct acpiphp_context *acpiphp_init_context(acpi_handle handle) | |
81 | { | |
82 | struct acpiphp_context *context; | |
83 | acpi_status status; | |
84 | ||
85 | context = kzalloc(sizeof(*context), GFP_KERNEL); | |
86 | if (!context) | |
87 | return NULL; | |
88 | ||
89 | context->handle = handle; | |
90 | context->refcount = 1; | |
91 | status = acpi_attach_data(handle, acpiphp_context_handler, context); | |
92 | if (ACPI_FAILURE(status)) { | |
93 | kfree(context); | |
94 | return NULL; | |
95 | } | |
96 | return context; | |
97 | } | |
98 | ||
99 | /** | |
100 | * acpiphp_get_context - Get hotplug context and grab a reference to it. | |
101 | * @handle: ACPI object handle to get the context for. | |
102 | * | |
103 | * Call under acpiphp_context_lock. | |
104 | */ | |
105 | static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) | |
106 | { | |
107 | struct acpiphp_context *context = NULL; | |
108 | acpi_status status; | |
109 | void *data; | |
110 | ||
111 | status = acpi_get_data(handle, acpiphp_context_handler, &data); | |
112 | if (ACPI_SUCCESS(status)) { | |
113 | context = data; | |
114 | context->refcount++; | |
115 | } | |
116 | return context; | |
117 | } | |
118 | ||
119 | /** | |
120 | * acpiphp_put_context - Drop a reference to ACPI hotplug context. | |
121 | * @handle: ACPI object handle to put the context for. | |
122 | * | |
123 | * The context object is removed if there are no more references to it. | |
124 | * | |
125 | * Call under acpiphp_context_lock. | |
126 | */ | |
127 | static void acpiphp_put_context(struct acpiphp_context *context) | |
128 | { | |
129 | if (--context->refcount) | |
130 | return; | |
131 | ||
bd4674df | 132 | WARN_ON(context->bridge); |
cb7b8ced RW |
133 | acpi_detach_data(context->handle, acpiphp_context_handler); |
134 | kfree(context); | |
135 | } | |
136 | ||
3d54a316 JL |
137 | static inline void get_bridge(struct acpiphp_bridge *bridge) |
138 | { | |
139 | kref_get(&bridge->ref); | |
140 | } | |
141 | ||
142 | static inline void put_bridge(struct acpiphp_bridge *bridge) | |
143 | { | |
144 | kref_put(&bridge->ref, free_bridge); | |
145 | } | |
146 | ||
147 | static void free_bridge(struct kref *kref) | |
148 | { | |
cb7b8ced | 149 | struct acpiphp_context *context; |
3d54a316 JL |
150 | struct acpiphp_bridge *bridge; |
151 | struct acpiphp_slot *slot, *next; | |
152 | struct acpiphp_func *func, *tmp; | |
153 | ||
cb7b8ced RW |
154 | mutex_lock(&acpiphp_context_lock); |
155 | ||
3d54a316 JL |
156 | bridge = container_of(kref, struct acpiphp_bridge, ref); |
157 | ||
158 | list_for_each_entry_safe(slot, next, &bridge->slots, node) { | |
bd4674df RW |
159 | list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) |
160 | acpiphp_put_context(func_to_context(func)); | |
161 | ||
3d54a316 JL |
162 | kfree(slot); |
163 | } | |
164 | ||
87831273 | 165 | context = bridge->context; |
bbd34fcd RW |
166 | /* Root bridges will not have hotplug context. */ |
167 | if (context) { | |
168 | /* Release the reference taken by acpiphp_enumerate_slots(). */ | |
bda46dbb | 169 | put_bridge(context->func.parent); |
bbd34fcd RW |
170 | context->bridge = NULL; |
171 | acpiphp_put_context(context); | |
172 | } | |
cb7b8ced | 173 | |
3d54a316 JL |
174 | put_device(&bridge->pci_bus->dev); |
175 | pci_dev_put(bridge->pci_dev); | |
176 | kfree(bridge); | |
cb7b8ced RW |
177 | |
178 | mutex_unlock(&acpiphp_context_lock); | |
3d54a316 JL |
179 | } |
180 | ||
4e8662bb KA |
181 | /* |
182 | * the _DCK method can do funny things... and sometimes not | |
183 | * hah-hah funny. | |
184 | * | |
185 | * TBD - figure out a way to only call fixups for | |
186 | * systems that require them. | |
187 | */ | |
f09ce741 | 188 | static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) |
4e8662bb | 189 | { |
43e5c091 | 190 | struct acpiphp_context *context = data; |
bda46dbb | 191 | struct pci_bus *bus = context->func.slot->bus; |
4e8662bb KA |
192 | u32 buses; |
193 | ||
194 | if (!bus->self) | |
f09ce741 | 195 | return; |
4e8662bb KA |
196 | |
197 | /* fixup bad _DCK function that rewrites | |
198 | * secondary bridge on slot | |
199 | */ | |
200 | pci_read_config_dword(bus->self, | |
201 | PCI_PRIMARY_BUS, | |
202 | &buses); | |
203 | ||
b918c62e | 204 | if (((buses >> 8) & 0xff) != bus->busn_res.start) { |
4e8662bb | 205 | buses = (buses & 0xff000000) |
2a9d3521 | 206 | | ((unsigned int)(bus->primary) << 0) |
b918c62e YL |
207 | | ((unsigned int)(bus->busn_res.start) << 8) |
208 | | ((unsigned int)(bus->busn_res.end) << 16); | |
4e8662bb KA |
209 | pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); |
210 | } | |
4e8662bb KA |
211 | } |
212 | ||
af9d8adc RW |
213 | static void dock_event(acpi_handle handle, u32 type, void *data) |
214 | { | |
215 | struct acpiphp_context *context; | |
216 | ||
217 | mutex_lock(&acpiphp_context_lock); | |
218 | context = acpiphp_get_context(handle); | |
219 | if (!context || WARN_ON(context->handle != handle) | |
220 | || context->func.parent->is_going_away) { | |
221 | mutex_unlock(&acpiphp_context_lock); | |
222 | return; | |
223 | } | |
224 | get_bridge(context->func.parent); | |
225 | acpiphp_put_context(context); | |
226 | mutex_unlock(&acpiphp_context_lock); | |
227 | ||
228 | hotplug_event(handle, type, data); | |
229 | ||
230 | put_bridge(context->func.parent); | |
231 | } | |
4e8662bb | 232 | |
9c8b04be | 233 | static const struct acpi_dock_ops acpiphp_dock_ops = { |
f09ce741 | 234 | .fixup = post_dock_fixups, |
af9d8adc | 235 | .handler = dock_event, |
1253f7aa | 236 | }; |
1da177e4 | 237 | |
5ba113f7 JL |
238 | /* Check whether the PCI device is managed by native PCIe hotplug driver */ |
239 | static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) | |
240 | { | |
241 | u32 reg32; | |
242 | acpi_handle tmp; | |
243 | struct acpi_pci_root *root; | |
244 | ||
245 | /* Check whether the PCIe port supports native PCIe hotplug */ | |
246 | if (pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, ®32)) | |
247 | return false; | |
248 | if (!(reg32 & PCI_EXP_SLTCAP_HPC)) | |
249 | return false; | |
250 | ||
251 | /* | |
252 | * Check whether native PCIe hotplug has been enabled for | |
253 | * this PCIe hierarchy. | |
254 | */ | |
255 | tmp = acpi_find_root_bridge_handle(pdev); | |
256 | if (!tmp) | |
257 | return false; | |
258 | root = acpi_pci_find_root(tmp); | |
259 | if (!root) | |
260 | return false; | |
261 | if (!(root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) | |
262 | return false; | |
263 | ||
264 | return true; | |
265 | } | |
266 | ||
21a31013 RW |
267 | static void acpiphp_dock_init(void *data) |
268 | { | |
43e5c091 | 269 | struct acpiphp_context *context = data; |
21a31013 | 270 | |
bda46dbb | 271 | get_bridge(context->func.parent); |
21a31013 RW |
272 | } |
273 | ||
274 | static void acpiphp_dock_release(void *data) | |
275 | { | |
43e5c091 | 276 | struct acpiphp_context *context = data; |
21a31013 | 277 | |
bda46dbb | 278 | put_bridge(context->func.parent); |
21a31013 RW |
279 | } |
280 | ||
1da177e4 | 281 | /* callback routine to register each ACPI PCI slot object */ |
cb7b8ced RW |
282 | static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, |
283 | void **rv) | |
1da177e4 | 284 | { |
cb7b8ced RW |
285 | struct acpiphp_bridge *bridge = data; |
286 | struct acpiphp_context *context; | |
1da177e4 LT |
287 | struct acpiphp_slot *slot; |
288 | struct acpiphp_func *newfunc; | |
1da177e4 | 289 | acpi_status status = AE_OK; |
bbd34fcd RW |
290 | unsigned long long adr; |
291 | int device, function; | |
e8c331e9 | 292 | struct pci_bus *pbus = bridge->pci_bus; |
bbd34fcd | 293 | struct pci_dev *pdev = bridge->pci_dev; |
3b63aaa7 | 294 | u32 val; |
1da177e4 | 295 | |
bbd34fcd | 296 | if (pdev && device_is_managed_by_native_pciehp(pdev)) |
1da177e4 LT |
297 | return AE_OK; |
298 | ||
dfb117b3 BH |
299 | status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); |
300 | if (ACPI_FAILURE(status)) { | |
f26ca1d6 TK |
301 | if (status != AE_NOT_FOUND) |
302 | acpi_handle_warn(handle, | |
303 | "can't evaluate _ADR (%#x)\n", status); | |
dfb117b3 BH |
304 | return AE_OK; |
305 | } | |
306 | ||
307 | device = (adr >> 16) & 0xffff; | |
308 | function = adr & 0xffff; | |
309 | ||
cb7b8ced RW |
310 | mutex_lock(&acpiphp_context_lock); |
311 | context = acpiphp_init_context(handle); | |
312 | if (!context) { | |
313 | mutex_unlock(&acpiphp_context_lock); | |
314 | acpi_handle_err(handle, "No hotplug context\n"); | |
cb7b8ced RW |
315 | return AE_NOT_EXIST; |
316 | } | |
bd4674df | 317 | newfunc = &context->func; |
bd4674df | 318 | newfunc->function = function; |
bda46dbb | 319 | newfunc->parent = bridge; |
cb7b8ced RW |
320 | mutex_unlock(&acpiphp_context_lock); |
321 | ||
ecd046da | 322 | if (acpi_has_method(handle, "_EJ0")) |
20416ea5 | 323 | newfunc->flags = FUNC_HAS_EJ0; |
1da177e4 | 324 | |
ecd046da | 325 | if (acpi_has_method(handle, "_STA")) |
1da177e4 LT |
326 | newfunc->flags |= FUNC_HAS_STA; |
327 | ||
ecd046da | 328 | if (acpi_has_method(handle, "_DCK")) |
20416ea5 | 329 | newfunc->flags |= FUNC_HAS_DCK; |
20416ea5 | 330 | |
1da177e4 | 331 | /* search for objects that share the same slot */ |
ad41dd9d | 332 | list_for_each_entry(slot, &bridge->slots, node) |
bbd34fcd | 333 | if (slot->device == device) |
ac372338 | 334 | goto slot_found; |
1da177e4 | 335 | |
ac372338 RW |
336 | slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); |
337 | if (!slot) { | |
338 | status = AE_NO_MEMORY; | |
339 | goto err; | |
340 | } | |
341 | ||
bda46dbb | 342 | slot->bus = bridge->pci_bus; |
ac372338 | 343 | slot->device = device; |
ac372338 RW |
344 | INIT_LIST_HEAD(&slot->funcs); |
345 | mutex_init(&slot->crit_sect); | |
346 | ||
ac372338 | 347 | list_add_tail(&slot->node, &bridge->slots); |
1da177e4 | 348 | |
f7625980 | 349 | /* Register slots for ejectable functions only. */ |
bbd34fcd RW |
350 | if (acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle)) { |
351 | unsigned long long sun; | |
352 | int retval; | |
ac372338 | 353 | |
bbd34fcd RW |
354 | bridge->nr_slots++; |
355 | status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); | |
356 | if (ACPI_FAILURE(status)) | |
357 | sun = bridge->nr_slots; | |
358 | ||
bd950799 | 359 | pr_debug("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n", |
7342798d | 360 | sun, pci_domain_nr(pbus), pbus->number, device); |
bbd34fcd | 361 | |
7342798d | 362 | retval = acpiphp_register_hotplug_slot(slot, sun); |
bbd34fcd | 363 | if (retval) { |
1aaac071 | 364 | slot->slot = NULL; |
bbd34fcd RW |
365 | bridge->nr_slots--; |
366 | if (retval == -EBUSY) | |
bd950799 | 367 | pr_warn("Slot %llu already registered by another " |
7342798d | 368 | "hotplug driver\n", sun); |
bbd34fcd | 369 | else |
bd950799 | 370 | pr_warn("acpiphp_register_hotplug_slot failed " |
bbd34fcd RW |
371 | "(err code = 0x%x)\n", retval); |
372 | } | |
373 | /* Even if the slot registration fails, we can still use it. */ | |
1da177e4 LT |
374 | } |
375 | ||
ac372338 | 376 | slot_found: |
1da177e4 LT |
377 | newfunc->slot = slot; |
378 | list_add_tail(&newfunc->sibling, &slot->funcs); | |
379 | ||
3b63aaa7 JL |
380 | if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function), |
381 | &val, 60*1000)) | |
bc805a55 | 382 | slot->flags |= SLOT_ENABLED; |
1da177e4 | 383 | |
4e8662bb KA |
384 | if (is_dock_device(handle)) { |
385 | /* we don't want to call this device's _EJ0 | |
386 | * because we want the dock notify handler | |
387 | * to call it after it calls _DCK | |
20416ea5 KA |
388 | */ |
389 | newfunc->flags &= ~FUNC_HAS_EJ0; | |
4e8662bb | 390 | if (register_hotplug_dock_device(handle, |
43e5c091 | 391 | &acpiphp_dock_ops, context, |
21a31013 | 392 | acpiphp_dock_init, acpiphp_dock_release)) |
bd950799 | 393 | pr_debug("failed to register dock device\n"); |
20416ea5 KA |
394 | } |
395 | ||
1da177e4 | 396 | /* install notify handler */ |
20416ea5 | 397 | if (!(newfunc->flags & FUNC_HAS_DCK)) { |
87831273 RW |
398 | status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, |
399 | handle_hotplug_event, | |
400 | context); | |
bbd34fcd RW |
401 | if (ACPI_FAILURE(status)) |
402 | acpi_handle_err(handle, | |
403 | "failed to install notify handler\n"); | |
2e862c51 | 404 | } |
1da177e4 | 405 | |
2e862c51 | 406 | return AE_OK; |
e27da381 | 407 | |
cb7b8ced | 408 | err: |
cb7b8ced | 409 | mutex_lock(&acpiphp_context_lock); |
cb7b8ced RW |
410 | acpiphp_put_context(context); |
411 | mutex_unlock(&acpiphp_context_lock); | |
cb7b8ced | 412 | return status; |
1da177e4 LT |
413 | } |
414 | ||
42f49a6a RS |
415 | static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) |
416 | { | |
ed13febf RW |
417 | struct acpiphp_context *context; |
418 | struct acpiphp_bridge *bridge = NULL; | |
58c08628 | 419 | |
ed13febf RW |
420 | mutex_lock(&acpiphp_context_lock); |
421 | context = acpiphp_get_context(handle); | |
422 | if (context) { | |
423 | bridge = context->bridge; | |
424 | if (bridge) | |
3d54a316 | 425 | get_bridge(bridge); |
42f49a6a | 426 | |
ed13febf RW |
427 | acpiphp_put_context(context); |
428 | } | |
429 | mutex_unlock(&acpiphp_context_lock); | |
430 | return bridge; | |
42f49a6a | 431 | } |
1da177e4 | 432 | |
364d5094 | 433 | static void cleanup_bridge(struct acpiphp_bridge *bridge) |
1da177e4 | 434 | { |
3d54a316 JL |
435 | struct acpiphp_slot *slot; |
436 | struct acpiphp_func *func; | |
42f49a6a | 437 | acpi_status status; |
42f49a6a | 438 | |
3d54a316 JL |
439 | list_for_each_entry(slot, &bridge->slots, node) { |
440 | list_for_each_entry(func, &slot->funcs, sibling) { | |
5a3bc573 RW |
441 | acpi_handle handle = func_to_handle(func); |
442 | ||
443 | if (is_dock_device(handle)) | |
444 | unregister_hotplug_dock_device(handle); | |
445 | ||
20416ea5 | 446 | if (!(func->flags & FUNC_HAS_DCK)) { |
5a3bc573 | 447 | status = acpi_remove_notify_handler(handle, |
87831273 RW |
448 | ACPI_SYSTEM_NOTIFY, |
449 | handle_hotplug_event); | |
20416ea5 | 450 | if (ACPI_FAILURE(status)) |
bd950799 | 451 | pr_err("failed to remove notify handler\n"); |
20416ea5 | 452 | } |
42f49a6a | 453 | } |
9217a984 | 454 | slot->flags |= SLOT_IS_GOING_AWAY; |
1aaac071 RW |
455 | if (slot->slot) |
456 | acpiphp_unregister_hotplug_slot(slot); | |
42f49a6a RS |
457 | } |
458 | ||
3d54a316 | 459 | mutex_lock(&bridge_mutex); |
42f49a6a | 460 | list_del(&bridge->list); |
3d54a316 | 461 | mutex_unlock(&bridge_mutex); |
9217a984 | 462 | |
1b360f44 | 463 | mutex_lock(&acpiphp_context_lock); |
9217a984 | 464 | bridge->is_going_away = true; |
1b360f44 | 465 | mutex_unlock(&acpiphp_context_lock); |
1da177e4 LT |
466 | } |
467 | ||
15a1ae74 | 468 | /** |
26e6c66e | 469 | * acpiphp_max_busnr - return the highest reserved bus number under the given bus. |
15a1ae74 | 470 | * @bus: bus to start search with |
15a1ae74 KA |
471 | */ |
472 | static unsigned char acpiphp_max_busnr(struct pci_bus *bus) | |
473 | { | |
474 | struct list_head *tmp; | |
475 | unsigned char max, n; | |
476 | ||
477 | /* | |
478 | * pci_bus_max_busnr will return the highest | |
479 | * reserved busnr for all these children. | |
480 | * that is equivalent to the bus->subordinate | |
481 | * value. We don't want to use the parent's | |
482 | * bus->subordinate value because it could have | |
483 | * padding in it. | |
484 | */ | |
b918c62e | 485 | max = bus->busn_res.start; |
15a1ae74 KA |
486 | |
487 | list_for_each(tmp, &bus->children) { | |
488 | n = pci_bus_max_busnr(pci_bus_b(tmp)); | |
489 | if (n > max) | |
490 | max = n; | |
491 | } | |
492 | return max; | |
493 | } | |
494 | ||
15a1ae74 | 495 | /** |
236e2624 RW |
496 | * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree. |
497 | * @handle: ACPI device object handle to start from. | |
15a1ae74 | 498 | */ |
236e2624 | 499 | static void acpiphp_bus_trim(acpi_handle handle) |
15a1ae74 | 500 | { |
236e2624 | 501 | struct acpi_device *adev = NULL; |
15a1ae74 | 502 | |
236e2624 RW |
503 | acpi_bus_get_device(handle, &adev); |
504 | if (adev) | |
505 | acpi_bus_trim(adev); | |
15a1ae74 KA |
506 | } |
507 | ||
92c9be95 | 508 | /** |
236e2624 RW |
509 | * acpiphp_bus_add - Scan ACPI namespace subtree. |
510 | * @handle: ACPI object handle to start the scan from. | |
92c9be95 | 511 | */ |
236e2624 | 512 | static void acpiphp_bus_add(acpi_handle handle) |
92c9be95 | 513 | { |
bc805a55 RW |
514 | struct acpi_device *adev = NULL; |
515 | ||
236e2624 | 516 | acpi_bus_scan(handle); |
bc805a55 | 517 | acpi_bus_get_device(handle, &adev); |
202317a5 | 518 | if (acpi_device_enumerated(adev)) |
bc805a55 | 519 | acpi_device_set_power(adev, ACPI_STATE_D0); |
92c9be95 | 520 | } |
15a1ae74 | 521 | |
d0607050 SL |
522 | static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) |
523 | { | |
524 | struct acpiphp_func *func; | |
525 | union acpi_object params[2]; | |
526 | struct acpi_object_list arg_list; | |
527 | ||
528 | list_for_each_entry(func, &slot->funcs, sibling) { | |
529 | arg_list.count = 2; | |
530 | arg_list.pointer = params; | |
531 | params[0].type = ACPI_TYPE_INTEGER; | |
532 | params[0].integer.value = ACPI_ADR_SPACE_PCI_CONFIG; | |
533 | params[1].type = ACPI_TYPE_INTEGER; | |
534 | params[1].integer.value = 1; | |
535 | /* _REG is optional, we don't care about if there is failure */ | |
5a3bc573 RW |
536 | acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list, |
537 | NULL); | |
d0607050 SL |
538 | } |
539 | } | |
540 | ||
1f96a965 YL |
541 | static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) |
542 | { | |
543 | struct acpiphp_func *func; | |
544 | ||
1f96a965 YL |
545 | /* quirk, or pcie could set it already */ |
546 | if (dev->is_hotplug_bridge) | |
547 | return; | |
548 | ||
1f96a965 YL |
549 | list_for_each_entry(func, &slot->funcs, sibling) { |
550 | if (PCI_FUNC(dev->devfn) == func->function) { | |
bbd34fcd | 551 | dev->is_hotplug_bridge = 1; |
1f96a965 YL |
552 | break; |
553 | } | |
554 | } | |
555 | } | |
3b63aaa7 | 556 | |
a47d8c8e RW |
557 | static int acpiphp_rescan_slot(struct acpiphp_slot *slot) |
558 | { | |
559 | struct acpiphp_func *func; | |
560 | ||
561 | list_for_each_entry(func, &slot->funcs, sibling) | |
562 | acpiphp_bus_add(func_to_handle(func)); | |
563 | ||
564 | return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0)); | |
565 | } | |
566 | ||
1da177e4 | 567 | /** |
a1d0abce | 568 | * enable_slot - enable, configure a slot |
1da177e4 LT |
569 | * @slot: slot to be enabled |
570 | * | |
571 | * This function should be called per *physical slot*, | |
572 | * not per each slot object in ACPI namespace. | |
1da177e4 | 573 | */ |
a1d0abce | 574 | static void __ref enable_slot(struct acpiphp_slot *slot) |
1da177e4 | 575 | { |
1da177e4 | 576 | struct pci_dev *dev; |
bda46dbb | 577 | struct pci_bus *bus = slot->bus; |
1da177e4 | 578 | struct acpiphp_func *func; |
b91182a6 | 579 | int max, pass; |
d66ecb72 | 580 | LIST_HEAD(add_list); |
1da177e4 | 581 | |
ab122590 | 582 | acpiphp_rescan_slot(slot); |
15a1ae74 | 583 | max = acpiphp_max_busnr(bus); |
42f49a6a RS |
584 | for (pass = 0; pass < 2; pass++) { |
585 | list_for_each_entry(dev, &bus->devices, bus_list) { | |
586 | if (PCI_SLOT(dev->devfn) != slot->device) | |
587 | continue; | |
a1d0abce | 588 | |
42f49a6a | 589 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || |
c64b5eea | 590 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { |
42f49a6a | 591 | max = pci_scan_bridge(bus, dev, max, pass); |
1f96a965 YL |
592 | if (pass && dev->subordinate) { |
593 | check_hotplug_bridge(slot, dev); | |
d66ecb72 JL |
594 | pcibios_resource_survey_bus(dev->subordinate); |
595 | __pci_bus_size_bridges(dev->subordinate, | |
596 | &add_list); | |
1f96a965 | 597 | } |
c64b5eea | 598 | } |
42f49a6a | 599 | } |
1da177e4 | 600 | } |
d66ecb72 | 601 | __pci_bus_assign_resources(bus, &add_list, NULL); |
2dc41281 | 602 | |
8e5dce35 | 603 | acpiphp_sanitize_bus(bus); |
fca6825a | 604 | acpiphp_set_hpp_values(bus); |
d0607050 | 605 | acpiphp_set_acpi_region(slot); |
69643e48 IC |
606 | |
607 | list_for_each_entry(dev, &bus->devices, bus_list) { | |
608 | /* Assume that newly added devices are powered on already. */ | |
609 | if (!dev->is_added) | |
610 | dev->current_state = PCI_D0; | |
611 | } | |
612 | ||
42f49a6a RS |
613 | pci_bus_add_devices(bus); |
614 | ||
f382a086 | 615 | slot->flags |= SLOT_ENABLED; |
58c08628 | 616 | list_for_each_entry(func, &slot->funcs, sibling) { |
9d911d79 AC |
617 | dev = pci_get_slot(bus, PCI_DEVFN(slot->device, |
618 | func->function)); | |
f382a086 AK |
619 | if (!dev) { |
620 | /* Do not set SLOT_ENABLED flag if some funcs | |
621 | are not added. */ | |
622 | slot->flags &= (~SLOT_ENABLED); | |
551bcb75 | 623 | continue; |
f382a086 | 624 | } |
1da177e4 | 625 | } |
1da177e4 LT |
626 | } |
627 | ||
ce29ca3e AK |
628 | /* return first device in slot, acquiring a reference on it */ |
629 | static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) | |
630 | { | |
bda46dbb | 631 | struct pci_bus *bus = slot->bus; |
ce29ca3e AK |
632 | struct pci_dev *dev; |
633 | struct pci_dev *ret = NULL; | |
634 | ||
635 | down_read(&pci_bus_sem); | |
636 | list_for_each_entry(dev, &bus->devices, bus_list) | |
637 | if (PCI_SLOT(dev->devfn) == slot->device) { | |
638 | ret = pci_dev_get(dev); | |
639 | break; | |
640 | } | |
641 | up_read(&pci_bus_sem); | |
642 | ||
643 | return ret; | |
644 | } | |
645 | ||
1da177e4 | 646 | /** |
a1d0abce | 647 | * disable_slot - disable a slot |
26e6c66e | 648 | * @slot: ACPI PHP slot |
1da177e4 | 649 | */ |
a1d0abce | 650 | static void disable_slot(struct acpiphp_slot *slot) |
1da177e4 | 651 | { |
1da177e4 | 652 | struct acpiphp_func *func; |
9d911d79 | 653 | struct pci_dev *pdev; |
551bcb75 | 654 | |
ce29ca3e | 655 | /* |
a1d0abce | 656 | * enable_slot() enumerates all functions in this device via |
ce29ca3e AK |
657 | * pci_scan_slot(), whether they have associated ACPI hotplug |
658 | * methods (_EJ0, etc.) or not. Therefore, we remove all functions | |
659 | * here. | |
660 | */ | |
661 | while ((pdev = dev_in_slot(slot))) { | |
34e54843 | 662 | pci_stop_and_remove_bus_device(pdev); |
ce29ca3e | 663 | pci_dev_put(pdev); |
600812ec ST |
664 | } |
665 | ||
5a3bc573 RW |
666 | list_for_each_entry(func, &slot->funcs, sibling) |
667 | acpiphp_bus_trim(func_to_handle(func)); | |
1da177e4 LT |
668 | |
669 | slot->flags &= (~SLOT_ENABLED); | |
1da177e4 LT |
670 | } |
671 | ||
f244d8b6 RW |
672 | static bool acpiphp_no_hotplug(acpi_handle handle) |
673 | { | |
674 | struct acpi_device *adev = NULL; | |
675 | ||
676 | acpi_bus_get_device(handle, &adev); | |
677 | return adev && adev->flags.no_hotplug; | |
678 | } | |
679 | ||
680 | static bool slot_no_hotplug(struct acpiphp_slot *slot) | |
681 | { | |
682 | struct acpiphp_func *func; | |
683 | ||
684 | list_for_each_entry(func, &slot->funcs, sibling) | |
685 | if (acpiphp_no_hotplug(func_to_handle(func))) | |
686 | return true; | |
687 | ||
688 | return false; | |
689 | } | |
1da177e4 LT |
690 | |
691 | /** | |
692 | * get_slot_status - get ACPI slot status | |
26e6c66e | 693 | * @slot: ACPI PHP slot |
1da177e4 | 694 | * |
26e6c66e RD |
695 | * If a slot has _STA for each function and if any one of them |
696 | * returned non-zero status, return it. | |
1da177e4 | 697 | * |
26e6c66e RD |
698 | * If a slot doesn't have _STA and if any one of its functions' |
699 | * configuration space is configured, return 0x0f as a _STA. | |
1da177e4 | 700 | * |
26e6c66e | 701 | * Otherwise return 0. |
1da177e4 LT |
702 | */ |
703 | static unsigned int get_slot_status(struct acpiphp_slot *slot) | |
704 | { | |
27663c58 | 705 | unsigned long long sta = 0; |
1da177e4 LT |
706 | struct acpiphp_func *func; |
707 | ||
58c08628 | 708 | list_for_each_entry(func, &slot->funcs, sibling) { |
1da177e4 | 709 | if (func->flags & FUNC_HAS_STA) { |
5a3bc573 RW |
710 | acpi_status status; |
711 | ||
712 | status = acpi_evaluate_integer(func_to_handle(func), | |
713 | "_STA", NULL, &sta); | |
1da177e4 LT |
714 | if (ACPI_SUCCESS(status) && sta) |
715 | break; | |
716 | } else { | |
5a3bc573 RW |
717 | u32 dvid; |
718 | ||
bda46dbb | 719 | pci_bus_read_config_dword(slot->bus, |
1da177e4 LT |
720 | PCI_DEVFN(slot->device, |
721 | func->function), | |
722 | PCI_VENDOR_ID, &dvid); | |
723 | if (dvid != 0xffffffff) { | |
724 | sta = ACPI_STA_ALL; | |
725 | break; | |
726 | } | |
727 | } | |
728 | } | |
729 | ||
730 | return (unsigned int)sta; | |
731 | } | |
732 | ||
72820594 MW |
733 | static inline bool device_status_valid(unsigned int sta) |
734 | { | |
735 | /* | |
736 | * ACPI spec says that _STA may return bit 0 clear with bit 3 set | |
737 | * if the device is valid but does not require a device driver to be | |
738 | * loaded (Section 6.3.7 of ACPI 5.0A). | |
739 | */ | |
740 | unsigned int mask = ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_FUNCTIONING; | |
741 | return (sta & mask) == mask; | |
742 | } | |
743 | ||
4ebe3450 RW |
744 | /** |
745 | * trim_stale_devices - remove PCI devices that are not responding. | |
746 | * @dev: PCI device to start walking the hierarchy from. | |
747 | */ | |
748 | static void trim_stale_devices(struct pci_dev *dev) | |
749 | { | |
750 | acpi_handle handle = ACPI_HANDLE(&dev->dev); | |
751 | struct pci_bus *bus = dev->subordinate; | |
752 | bool alive = false; | |
753 | ||
754 | if (handle) { | |
755 | acpi_status status; | |
756 | unsigned long long sta; | |
757 | ||
758 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); | |
72820594 | 759 | alive = (ACPI_SUCCESS(status) && device_status_valid(sta)) |
f244d8b6 | 760 | || acpiphp_no_hotplug(handle); |
4ebe3450 RW |
761 | } |
762 | if (!alive) { | |
763 | u32 v; | |
764 | ||
765 | /* Check if the device responds. */ | |
766 | alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0); | |
767 | } | |
768 | if (!alive) { | |
769 | pci_stop_and_remove_bus_device(dev); | |
770 | if (handle) | |
771 | acpiphp_bus_trim(handle); | |
772 | } else if (bus) { | |
773 | struct pci_dev *child, *tmp; | |
774 | ||
775 | /* The device is a bridge. so check the bus below it. */ | |
776 | pm_runtime_get_sync(&dev->dev); | |
2d7c1b77 | 777 | list_for_each_entry_safe_reverse(child, tmp, &bus->devices, bus_list) |
4ebe3450 RW |
778 | trim_stale_devices(child); |
779 | ||
780 | pm_runtime_put(&dev->dev); | |
781 | } | |
782 | } | |
783 | ||
1da177e4 LT |
784 | /** |
785 | * acpiphp_check_bridge - re-enumerate devices | |
26e6c66e | 786 | * @bridge: where to begin re-enumeration |
1da177e4 LT |
787 | * |
788 | * Iterate over all slots under this bridge and make sure that if a | |
789 | * card is present they are enabled, and if not they are disabled. | |
790 | */ | |
4ebe3450 | 791 | static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) |
1da177e4 LT |
792 | { |
793 | struct acpiphp_slot *slot; | |
1da177e4 | 794 | |
9217a984 RW |
795 | /* Bail out if the bridge is going away. */ |
796 | if (bridge->is_going_away) | |
797 | return; | |
798 | ||
ad41dd9d | 799 | list_for_each_entry(slot, &bridge->slots, node) { |
4ebe3450 RW |
800 | struct pci_bus *bus = slot->bus; |
801 | struct pci_dev *dev, *tmp; | |
802 | ||
803 | mutex_lock(&slot->crit_sect); | |
f244d8b6 RW |
804 | if (slot_no_hotplug(slot)) { |
805 | ; /* do nothing */ | |
72820594 | 806 | } else if (device_status_valid(get_slot_status(slot))) { |
4ebe3450 | 807 | /* remove stale devices if any */ |
2d7c1b77 RW |
808 | list_for_each_entry_safe_reverse(dev, tmp, |
809 | &bus->devices, bus_list) | |
4ebe3450 RW |
810 | if (PCI_SLOT(dev->devfn) == slot->device) |
811 | trim_stale_devices(dev); | |
812 | ||
813 | /* configure all functions */ | |
a1d0abce | 814 | enable_slot(slot); |
1da177e4 | 815 | } else { |
a1d0abce | 816 | disable_slot(slot); |
1da177e4 | 817 | } |
4ebe3450 | 818 | mutex_unlock(&slot->crit_sect); |
1da177e4 | 819 | } |
1da177e4 LT |
820 | } |
821 | ||
fca6825a | 822 | static void acpiphp_set_hpp_values(struct pci_bus *bus) |
8e7561cf | 823 | { |
8e7561cf RS |
824 | struct pci_dev *dev; |
825 | ||
e81995bb BH |
826 | list_for_each_entry(dev, &bus->devices, bus_list) |
827 | pci_configure_slot(dev); | |
8e7561cf RS |
828 | } |
829 | ||
830 | /* | |
831 | * Remove devices for which we could not assign resources, call | |
832 | * arch specific code to fix-up the bus | |
833 | */ | |
834 | static void acpiphp_sanitize_bus(struct pci_bus *bus) | |
835 | { | |
d65eba6a | 836 | struct pci_dev *dev, *tmp; |
8e7561cf RS |
837 | int i; |
838 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; | |
839 | ||
2d7c1b77 | 840 | list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) { |
8e7561cf RS |
841 | for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { |
842 | struct resource *res = &dev->resource[i]; | |
843 | if ((res->flags & type_mask) && !res->start && | |
844 | res->end) { | |
845 | /* Could not assign a required resources | |
846 | * for this device, remove it */ | |
210647af | 847 | pci_stop_and_remove_bus_device(dev); |
8e7561cf RS |
848 | break; |
849 | } | |
850 | } | |
851 | } | |
852 | } | |
853 | ||
1da177e4 LT |
854 | /* |
855 | * ACPI event handlers | |
856 | */ | |
857 | ||
3f327e39 YL |
858 | void acpiphp_check_host_bridge(acpi_handle handle) |
859 | { | |
860 | struct acpiphp_bridge *bridge; | |
861 | ||
862 | bridge = acpiphp_handle_to_bridge(handle); | |
863 | if (bridge) { | |
d42f5da2 RW |
864 | pci_lock_rescan_remove(); |
865 | ||
3f327e39 | 866 | acpiphp_check_bridge(bridge); |
d42f5da2 RW |
867 | |
868 | pci_unlock_rescan_remove(); | |
3f327e39 YL |
869 | put_bridge(bridge); |
870 | } | |
3f327e39 YL |
871 | } |
872 | ||
9217a984 RW |
873 | static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); |
874 | ||
43e5c091 | 875 | static void hotplug_event(acpi_handle handle, u32 type, void *data) |
1da177e4 | 876 | { |
43e5c091 | 877 | struct acpiphp_context *context = data; |
bd4674df | 878 | struct acpiphp_func *func = &context->func; |
1da177e4 LT |
879 | struct acpiphp_bridge *bridge; |
880 | char objname[64]; | |
881 | struct acpi_buffer buffer = { .length = sizeof(objname), | |
882 | .pointer = objname }; | |
6af8bef1 | 883 | |
43e5c091 | 884 | mutex_lock(&acpiphp_context_lock); |
c8ebcf1f | 885 | bridge = context->bridge; |
43e5c091 RW |
886 | if (bridge) |
887 | get_bridge(bridge); | |
1da177e4 | 888 | |
43e5c091 | 889 | mutex_unlock(&acpiphp_context_lock); |
3757b948 | 890 | |
f41b3261 | 891 | pci_lock_rescan_remove(); |
1da177e4 LT |
892 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); |
893 | ||
894 | switch (type) { | |
895 | case ACPI_NOTIFY_BUS_CHECK: | |
896 | /* bus re-enumerate */ | |
bd950799 LT |
897 | pr_debug("%s: Bus check notify on %s\n", __func__, objname); |
898 | pr_debug("%s: re-enumerating slots under %s\n", | |
899 | __func__, objname); | |
43e5c091 RW |
900 | if (bridge) { |
901 | acpiphp_check_bridge(bridge); | |
43e5c091 | 902 | } else { |
4ebe3450 RW |
903 | struct acpiphp_slot *slot = func->slot; |
904 | ||
9217a984 RW |
905 | if (slot->flags & SLOT_IS_GOING_AWAY) |
906 | break; | |
907 | ||
4ebe3450 | 908 | mutex_lock(&slot->crit_sect); |
a1d0abce | 909 | enable_slot(slot); |
4ebe3450 | 910 | mutex_unlock(&slot->crit_sect); |
43e5c091 | 911 | } |
1da177e4 LT |
912 | break; |
913 | ||
914 | case ACPI_NOTIFY_DEVICE_CHECK: | |
915 | /* device check */ | |
bd950799 | 916 | pr_debug("%s: Device check notify on %s\n", __func__, objname); |
a47d8c8e | 917 | if (bridge) { |
43e5c091 | 918 | acpiphp_check_bridge(bridge); |
a47d8c8e RW |
919 | } else { |
920 | struct acpiphp_slot *slot = func->slot; | |
921 | int ret; | |
43e5c091 | 922 | |
9217a984 RW |
923 | if (slot->flags & SLOT_IS_GOING_AWAY) |
924 | break; | |
925 | ||
a47d8c8e RW |
926 | /* |
927 | * Check if anything has changed in the slot and rescan | |
928 | * from the parent if that's the case. | |
929 | */ | |
930 | mutex_lock(&slot->crit_sect); | |
931 | ret = acpiphp_rescan_slot(slot); | |
932 | mutex_unlock(&slot->crit_sect); | |
933 | if (ret) | |
934 | acpiphp_check_bridge(func->parent); | |
935 | } | |
1da177e4 LT |
936 | break; |
937 | ||
1da177e4 LT |
938 | case ACPI_NOTIFY_EJECT_REQUEST: |
939 | /* request device eject */ | |
bd950799 | 940 | pr_debug("%s: Device eject notify on %s\n", __func__, objname); |
ad21d2d0 | 941 | acpiphp_disable_and_eject_slot(func->slot); |
1da177e4 | 942 | break; |
1da177e4 | 943 | } |
6af8bef1 | 944 | |
f41b3261 | 945 | pci_unlock_rescan_remove(); |
43e5c091 RW |
946 | if (bridge) |
947 | put_bridge(bridge); | |
21a31013 RW |
948 | } |
949 | ||
7b98118a | 950 | static void hotplug_event_work(void *data, u32 type) |
21a31013 | 951 | { |
7b98118a RW |
952 | struct acpiphp_context *context = data; |
953 | acpi_handle handle = context->handle; | |
21a31013 | 954 | |
21a31013 RW |
955 | acpi_scan_lock_acquire(); |
956 | ||
7b98118a | 957 | hotplug_event(handle, type, context); |
6af8bef1 | 958 | |
3757b948 | 959 | acpi_scan_lock_release(); |
7b98118a | 960 | acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); |
bda46dbb | 961 | put_bridge(context->func.parent); |
1da177e4 LT |
962 | } |
963 | ||
6af8bef1 | 964 | /** |
87831273 | 965 | * handle_hotplug_event - handle ACPI hotplug event |
6af8bef1 PB |
966 | * @handle: Notify()'ed acpi_handle |
967 | * @type: Notify code | |
87831273 | 968 | * @data: pointer to acpiphp_context structure |
6af8bef1 PB |
969 | * |
970 | * Handles ACPI event notification on slots. | |
971 | */ | |
87831273 | 972 | static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) |
6af8bef1 | 973 | { |
87831273 | 974 | struct acpiphp_context *context; |
e532e84e | 975 | u32 ost_code = ACPI_OST_SC_SUCCESS; |
1b360f44 | 976 | acpi_status status; |
87831273 | 977 | |
5c8d0e1d RW |
978 | switch (type) { |
979 | case ACPI_NOTIFY_BUS_CHECK: | |
980 | case ACPI_NOTIFY_DEVICE_CHECK: | |
e532e84e | 981 | break; |
5c8d0e1d | 982 | case ACPI_NOTIFY_EJECT_REQUEST: |
e532e84e RW |
983 | ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; |
984 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); | |
5c8d0e1d RW |
985 | break; |
986 | ||
987 | case ACPI_NOTIFY_DEVICE_WAKE: | |
988 | return; | |
989 | ||
990 | case ACPI_NOTIFY_FREQUENCY_MISMATCH: | |
991 | acpi_handle_err(handle, "Device cannot be configured due " | |
992 | "to a frequency mismatch\n"); | |
e532e84e | 993 | goto out; |
5c8d0e1d RW |
994 | |
995 | case ACPI_NOTIFY_BUS_MODE_MISMATCH: | |
996 | acpi_handle_err(handle, "Device cannot be configured due " | |
997 | "to a bus mode mismatch\n"); | |
e532e84e | 998 | goto out; |
5c8d0e1d RW |
999 | |
1000 | case ACPI_NOTIFY_POWER_FAULT: | |
1001 | acpi_handle_err(handle, "Device has suffered a power fault\n"); | |
e532e84e | 1002 | goto out; |
5c8d0e1d RW |
1003 | |
1004 | default: | |
1005 | acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); | |
e532e84e RW |
1006 | ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; |
1007 | goto out; | |
5c8d0e1d RW |
1008 | } |
1009 | ||
87831273 RW |
1010 | mutex_lock(&acpiphp_context_lock); |
1011 | context = acpiphp_get_context(handle); | |
1b360f44 RW |
1012 | if (!context || WARN_ON(context->handle != handle) |
1013 | || context->func.parent->is_going_away) | |
1014 | goto err_out; | |
1015 | ||
1016 | get_bridge(context->func.parent); | |
1017 | acpiphp_put_context(context); | |
1018 | status = acpi_hotplug_execute(hotplug_event_work, context, type); | |
1019 | if (ACPI_SUCCESS(status)) { | |
e532e84e RW |
1020 | mutex_unlock(&acpiphp_context_lock); |
1021 | return; | |
87831273 | 1022 | } |
1b360f44 RW |
1023 | put_bridge(context->func.parent); |
1024 | ||
1025 | err_out: | |
87831273 | 1026 | mutex_unlock(&acpiphp_context_lock); |
e532e84e RW |
1027 | ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; |
1028 | ||
1029 | out: | |
1030 | acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); | |
8e7561cf | 1031 | } |
1da177e4 | 1032 | |
3b63aaa7 JL |
1033 | /* |
1034 | * Create hotplug slots for the PCI bus. | |
1035 | * It should always return 0 to avoid skipping following notifiers. | |
1da177e4 | 1036 | */ |
be1c9de9 | 1037 | void acpiphp_enumerate_slots(struct pci_bus *bus) |
1da177e4 | 1038 | { |
3b63aaa7 | 1039 | struct acpiphp_bridge *bridge; |
2552002a RW |
1040 | acpi_handle handle; |
1041 | acpi_status status; | |
1da177e4 | 1042 | |
3b63aaa7 JL |
1043 | if (acpiphp_disabled) |
1044 | return; | |
1da177e4 | 1045 | |
be1c9de9 | 1046 | handle = ACPI_HANDLE(bus->bridge); |
bbd34fcd | 1047 | if (!handle) |
3b63aaa7 | 1048 | return; |
1da177e4 | 1049 | |
3b63aaa7 | 1050 | bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); |
cb7b8ced RW |
1051 | if (!bridge) { |
1052 | acpi_handle_err(handle, "No memory for bridge object\n"); | |
3b63aaa7 JL |
1053 | return; |
1054 | } | |
1055 | ||
ad41dd9d | 1056 | INIT_LIST_HEAD(&bridge->slots); |
3d54a316 | 1057 | kref_init(&bridge->ref); |
3b63aaa7 JL |
1058 | bridge->pci_dev = pci_dev_get(bus->self); |
1059 | bridge->pci_bus = bus; | |
1060 | ||
1061 | /* | |
1062 | * Grab a ref to the subordinate PCI bus in case the bus is | |
1063 | * removed via PCI core logical hotplug. The ref pins the bus | |
1064 | * (which we access during module unload). | |
1065 | */ | |
1066 | get_device(&bus->dev); | |
1067 | ||
bbd34fcd RW |
1068 | if (!pci_is_root_bus(bridge->pci_bus)) { |
1069 | struct acpiphp_context *context; | |
1070 | ||
1071 | /* | |
1072 | * This bridge should have been registered as a hotplug function | |
fd3cfebe RW |
1073 | * under its parent, so the context should be there, unless the |
1074 | * parent is going to be handled by pciehp, in which case this | |
1075 | * bridge is not interesting to us either. | |
bbd34fcd RW |
1076 | */ |
1077 | mutex_lock(&acpiphp_context_lock); | |
1078 | context = acpiphp_get_context(handle); | |
fd3cfebe | 1079 | if (!context) { |
bbd34fcd RW |
1080 | mutex_unlock(&acpiphp_context_lock); |
1081 | put_device(&bus->dev); | |
5d449457 | 1082 | pci_dev_put(bridge->pci_dev); |
bbd34fcd RW |
1083 | kfree(bridge); |
1084 | return; | |
1085 | } | |
1086 | bridge->context = context; | |
1087 | context->bridge = bridge; | |
1088 | /* Get a reference to the parent bridge. */ | |
bda46dbb | 1089 | get_bridge(context->func.parent); |
bbd34fcd RW |
1090 | mutex_unlock(&acpiphp_context_lock); |
1091 | } | |
1092 | ||
2552002a RW |
1093 | /* must be added to the list prior to calling register_slot */ |
1094 | mutex_lock(&bridge_mutex); | |
1095 | list_add(&bridge->list, &bridge_list); | |
1096 | mutex_unlock(&bridge_mutex); | |
1097 | ||
1098 | /* register all slot objects under this bridge */ | |
89373a55 | 1099 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, |
2552002a RW |
1100 | register_slot, NULL, bridge, NULL); |
1101 | if (ACPI_FAILURE(status)) { | |
89373a55 | 1102 | acpi_handle_err(handle, "failed to register slots\n"); |
bbd34fcd RW |
1103 | cleanup_bridge(bridge); |
1104 | put_bridge(bridge); | |
2552002a | 1105 | } |
3b63aaa7 JL |
1106 | } |
1107 | ||
1108 | /* Destroy hotplug slots associated with the PCI bus */ | |
1109 | void acpiphp_remove_slots(struct pci_bus *bus) | |
1da177e4 | 1110 | { |
ff181e5a | 1111 | struct acpiphp_bridge *bridge; |
3b63aaa7 JL |
1112 | |
1113 | if (acpiphp_disabled) | |
1114 | return; | |
1115 | ||
ff181e5a RW |
1116 | mutex_lock(&bridge_mutex); |
1117 | list_for_each_entry(bridge, &bridge_list, list) | |
3b63aaa7 | 1118 | if (bridge->pci_bus == bus) { |
ff181e5a | 1119 | mutex_unlock(&bridge_mutex); |
3b63aaa7 | 1120 | cleanup_bridge(bridge); |
3d54a316 | 1121 | put_bridge(bridge); |
ff181e5a | 1122 | return; |
3b63aaa7 | 1123 | } |
ff181e5a RW |
1124 | |
1125 | mutex_unlock(&bridge_mutex); | |
1da177e4 LT |
1126 | } |
1127 | ||
1da177e4 LT |
1128 | /** |
1129 | * acpiphp_enable_slot - power on slot | |
26e6c66e | 1130 | * @slot: ACPI PHP slot |
1da177e4 LT |
1131 | */ |
1132 | int acpiphp_enable_slot(struct acpiphp_slot *slot) | |
1133 | { | |
9217a984 RW |
1134 | pci_lock_rescan_remove(); |
1135 | ||
1136 | if (slot->flags & SLOT_IS_GOING_AWAY) | |
1137 | return -ENODEV; | |
1138 | ||
6aa4cdd0 | 1139 | mutex_lock(&slot->crit_sect); |
bc805a55 | 1140 | /* configure all functions */ |
55502ddb | 1141 | if (!(slot->flags & SLOT_ENABLED)) |
a1d0abce | 1142 | enable_slot(slot); |
55502ddb | 1143 | |
6aa4cdd0 | 1144 | mutex_unlock(&slot->crit_sect); |
9217a984 RW |
1145 | |
1146 | pci_unlock_rescan_remove(); | |
a1d0abce | 1147 | return 0; |
1da177e4 LT |
1148 | } |
1149 | ||
1da177e4 | 1150 | /** |
ad21d2d0 | 1151 | * acpiphp_disable_and_eject_slot - power off and eject slot |
26e6c66e | 1152 | * @slot: ACPI PHP slot |
1da177e4 | 1153 | */ |
9217a984 | 1154 | static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) |
1da177e4 | 1155 | { |
ad21d2d0 | 1156 | struct acpiphp_func *func; |
9217a984 RW |
1157 | |
1158 | if (slot->flags & SLOT_IS_GOING_AWAY) | |
1159 | return -ENODEV; | |
1da177e4 | 1160 | |
6aa4cdd0 | 1161 | mutex_lock(&slot->crit_sect); |
1da177e4 LT |
1162 | |
1163 | /* unconfigure all functions */ | |
a1d0abce | 1164 | disable_slot(slot); |
1da177e4 | 1165 | |
ad21d2d0 MW |
1166 | list_for_each_entry(func, &slot->funcs, sibling) |
1167 | if (func->flags & FUNC_HAS_EJ0) { | |
1168 | acpi_handle handle = func_to_handle(func); | |
1169 | ||
1170 | if (ACPI_FAILURE(acpi_evaluate_ej0(handle))) | |
1171 | acpi_handle_err(handle, "_EJ0 failed\n"); | |
1172 | ||
1173 | break; | |
1174 | } | |
1175 | ||
6aa4cdd0 | 1176 | mutex_unlock(&slot->crit_sect); |
9217a984 | 1177 | return 0; |
1da177e4 LT |
1178 | } |
1179 | ||
9217a984 RW |
1180 | int acpiphp_disable_slot(struct acpiphp_slot *slot) |
1181 | { | |
1182 | int ret; | |
1183 | ||
1184 | pci_lock_rescan_remove(); | |
1185 | ret = acpiphp_disable_and_eject_slot(slot); | |
1186 | pci_unlock_rescan_remove(); | |
1187 | return ret; | |
1188 | } | |
1da177e4 LT |
1189 | |
1190 | /* | |
1191 | * slot enabled: 1 | |
1192 | * slot disabled: 0 | |
1193 | */ | |
1194 | u8 acpiphp_get_power_status(struct acpiphp_slot *slot) | |
1195 | { | |
bc805a55 | 1196 | return (slot->flags & SLOT_ENABLED); |
1da177e4 LT |
1197 | } |
1198 | ||
1da177e4 | 1199 | /* |
35ae61a0 MT |
1200 | * latch open: 1 |
1201 | * latch closed: 0 | |
1da177e4 LT |
1202 | */ |
1203 | u8 acpiphp_get_latch_status(struct acpiphp_slot *slot) | |
1204 | { | |
1ad3790a | 1205 | return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI); |
1da177e4 LT |
1206 | } |
1207 | ||
1da177e4 LT |
1208 | /* |
1209 | * adapter presence : 1 | |
1210 | * absence : 0 | |
1211 | */ | |
1212 | u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) | |
1213 | { | |
1ad3790a | 1214 | return !!get_slot_status(slot); |
1da177e4 | 1215 | } |