aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/acpiphp.h8
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c129
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c48
3 files changed, 87 insertions, 98 deletions
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 885838a2e93f..de9df80ffb50 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -60,10 +60,7 @@ struct acpiphp_slot;
60 * struct slot - slot information for each *physical* slot 60 * struct slot - slot information for each *physical* slot
61 */ 61 */
62struct slot { 62struct slot {
63 u8 number;
64 struct hotplug_slot *hotplug_slot; 63 struct hotplug_slot *hotplug_slot;
65 struct list_head slot_list;
66
67 struct acpiphp_slot *acpi_slot; 64 struct acpiphp_slot *acpi_slot;
68}; 65};
69 66
@@ -119,9 +116,9 @@ struct acpiphp_slot {
119 struct acpiphp_bridge *bridge; /* parent */ 116 struct acpiphp_bridge *bridge; /* parent */
120 struct list_head funcs; /* one slot may have different 117 struct list_head funcs; /* one slot may have different
121 objects (i.e. for each function) */ 118 objects (i.e. for each function) */
119 struct slot *slot;
122 struct mutex crit_sect; 120 struct mutex crit_sect;
123 121
124 u32 id; /* slot id (serial #) for hotplug core */
125 u8 device; /* pci device# */ 122 u8 device; /* pci device# */
126 123
127 u32 sun; /* ACPI _SUN (slot unique number) */ 124 u32 sun; /* ACPI _SUN (slot unique number) */
@@ -229,12 +226,13 @@ struct acpiphp_dock_station {
229/* acpiphp_core.c */ 226/* acpiphp_core.c */
230extern int acpiphp_register_attention(struct acpiphp_attention_info*info); 227extern int acpiphp_register_attention(struct acpiphp_attention_info*info);
231extern int acpiphp_unregister_attention(struct acpiphp_attention_info *info); 228extern int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
229extern int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
230extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
232 231
233/* acpiphp_glue.c */ 232/* acpiphp_glue.c */
234extern int acpiphp_glue_init (void); 233extern int acpiphp_glue_init (void);
235extern void acpiphp_glue_exit (void); 234extern void acpiphp_glue_exit (void);
236extern int acpiphp_get_num_slots (void); 235extern int acpiphp_get_num_slots (void);
237extern struct acpiphp_slot *get_slot_from_id (int id);
238typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); 236typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
239void handle_hotplug_event_func(acpi_handle, u32, void*); 237void handle_hotplug_event_func(acpi_handle, u32, void*);
240 238
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index bce71c933478..4f1b0da8e47e 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -44,8 +44,6 @@
44#include "pci_hotplug.h" 44#include "pci_hotplug.h"
45#include "acpiphp.h" 45#include "acpiphp.h"
46 46
47static LIST_HEAD(slot_list);
48
49#define MY_NAME "acpiphp" 47#define MY_NAME "acpiphp"
50 48
51static int debug; 49static int debug;
@@ -341,62 +339,53 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
341 kfree(slot); 339 kfree(slot);
342} 340}
343 341
344/** 342/* callback routine to initialize 'struct slot' for each slot */
345 * init_slots - initialize 'struct slot' structures for each slot 343int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
346 *
347 */
348static int __init init_slots(void)
349{ 344{
350 struct slot *slot; 345 struct slot *slot;
346 struct hotplug_slot *hotplug_slot;
347 struct hotplug_slot_info *hotplug_slot_info;
351 int retval = -ENOMEM; 348 int retval = -ENOMEM;
352 int i; 349
353 350 slot = kzalloc(sizeof(*slot), GFP_KERNEL);
354 for (i = 0; i < num_slots; ++i) { 351 if (!slot)
355 slot = kmalloc(sizeof(struct slot), GFP_KERNEL); 352 goto error;
356 if (!slot) 353
357 goto error; 354 slot->hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
358 memset(slot, 0, sizeof(struct slot)); 355 if (!slot->hotplug_slot)
359 356 goto error_slot;
360 slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL); 357
361 if (!slot->hotplug_slot) 358 slot->hotplug_slot->info = kzalloc(sizeof(*hotplug_slot_info),
362 goto error_slot; 359 GFP_KERNEL);
363 memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); 360 if (!slot->hotplug_slot->info)
364 361 goto error_hpslot;
365 slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); 362
366 if (!slot->hotplug_slot->info) 363 slot->hotplug_slot->name = kzalloc(SLOT_NAME_SIZE, GFP_KERNEL);
367 goto error_hpslot; 364 if (!slot->hotplug_slot->name)
368 memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info)); 365 goto error_info;
369 366
370 slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); 367 slot->hotplug_slot->private = slot;
371 if (!slot->hotplug_slot->name) 368 slot->hotplug_slot->release = &release_slot;
372 goto error_info; 369 slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
373 370
374 slot->number = i; 371 slot->acpi_slot = acpiphp_slot;
375 372 slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
376 slot->hotplug_slot->private = slot; 373 slot->hotplug_slot->info->attention_status = 0;
377 slot->hotplug_slot->release = &release_slot; 374 slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
378 slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; 375 slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
379 376 slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
380 slot->acpi_slot = get_slot_from_id(i); 377 slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
381 slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); 378
382 slot->hotplug_slot->info->attention_status = 0; 379 acpiphp_slot->slot = slot;
383 slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); 380 make_slot_name(slot);
384 slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); 381
385 slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; 382 retval = pci_hp_register(slot->hotplug_slot);
386 slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; 383 if (retval) {
387 384 err("pci_hp_register failed with error %d\n", retval);
388 make_slot_name(slot); 385 goto error_name;
389 386 }
390 retval = pci_hp_register(slot->hotplug_slot); 387
391 if (retval) { 388 info("Slot [%s] registered\n", slot->hotplug_slot->name);
392 err("pci_hp_register failed with error %d\n", retval);
393 goto error_name;
394 }
395
396 /* add slot to our internal list */
397 list_add(&slot->slot_list, &slot_list);
398 info("Slot [%s] registered\n", slot->hotplug_slot->name);
399 }
400 389
401 return 0; 390 return 0;
402error_name: 391error_name:
@@ -412,17 +401,16 @@ error:
412} 401}
413 402
414 403
415static void __exit cleanup_slots (void) 404void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
416{ 405{
417 struct list_head *tmp, *n; 406 struct slot *slot = acpiphp_slot->slot;
418 struct slot *slot; 407 int retval = 0;
419 408
420 list_for_each_safe (tmp, n, &slot_list) { 409 info ("Slot [%s] unregistered\n", slot->hotplug_slot->name);
421 /* memory will be freed in release_slot callback */ 410
422 slot = list_entry(tmp, struct slot, slot_list); 411 retval = pci_hp_deregister(slot->hotplug_slot);
423 list_del(&slot->slot_list); 412 if (retval)
424 pci_hp_deregister(slot->hotplug_slot); 413 err("pci_hp_deregister failed with error %d\n", retval);
425 }
426} 414}
427 415
428 416
@@ -439,16 +427,21 @@ static int __init acpiphp_init(void)
439 427
440 /* read all the ACPI info from the system */ 428 /* read all the ACPI info from the system */
441 retval = init_acpi(); 429 retval = init_acpi();
442 if (retval && !(docking_station))
443 return retval;
444 430
445 return init_slots(); 431 /* if we have found a docking station, we should
432 * go ahead and load even if init_acpi has found
433 * no slots. This handles the case when the _DCK
434 * method not defined under the actual dock bridge
435 */
436 if (docking_station)
437 return 0;
438 else
439 return retval;
446} 440}
447 441
448 442
449static void __exit acpiphp_exit(void) 443static void __exit acpiphp_exit(void)
450{ 444{
451 cleanup_slots();
452 /* deallocate internal data structures etc. */ 445 /* deallocate internal data structures etc. */
453 acpiphp_glue_exit(); 446 acpiphp_glue_exit();
454 447
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 22d0f1cf1362..dbfdac63cb49 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -128,8 +128,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
128 acpi_handle tmp; 128 acpi_handle tmp;
129 acpi_status status = AE_OK; 129 acpi_status status = AE_OK;
130 unsigned long adr, sun; 130 unsigned long adr, sun;
131 int device, function; 131 int device, function, retval;
132 static int num_slots = 0; /* XXX if we support I/O node hotplug... */
133 132
134 status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); 133 status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
135 134
@@ -198,7 +197,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
198 197
199 memset(slot, 0, sizeof(struct acpiphp_slot)); 198 memset(slot, 0, sizeof(struct acpiphp_slot));
200 slot->bridge = bridge; 199 slot->bridge = bridge;
201 slot->id = num_slots++;
202 slot->device = device; 200 slot->device = device;
203 slot->sun = sun; 201 slot->sun = sun;
204 INIT_LIST_HEAD(&slot->funcs); 202 INIT_LIST_HEAD(&slot->funcs);
@@ -212,6 +210,11 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
212 dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n", 210 dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n",
213 slot->sun, pci_domain_nr(bridge->pci_bus), 211 slot->sun, pci_domain_nr(bridge->pci_bus),
214 bridge->pci_bus->number, slot->device); 212 bridge->pci_bus->number, slot->device);
213 retval = acpiphp_register_hotplug_slot(slot);
214 if (retval) {
215 warn("acpiphp_register_hotplug_slot failed(err code = 0x%x)\n", retval);
216 goto err_exit;
217 }
215 } 218 }
216 219
217 newfunc->slot = slot; 220 newfunc->slot = slot;
@@ -253,6 +256,14 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
253 status = AE_OK; 256 status = AE_OK;
254 257
255 return status; 258 return status;
259
260 err_exit:
261 bridge->nr_slots--;
262 bridge->slots = slot->next;
263 kfree(slot);
264 kfree(newfunc);
265
266 return AE_OK;
256} 267}
257 268
258 269
@@ -335,9 +346,16 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
335 /* decode ACPI 2.0 _HPP (hot plug parameters) */ 346 /* decode ACPI 2.0 _HPP (hot plug parameters) */
336 decode_hpp(bridge); 347 decode_hpp(bridge);
337 348
349 /* must be added to the list prior to calling register_slot */
350 list_add(&bridge->list, &bridge_list);
351
338 /* register all slot objects under this bridge */ 352 /* register all slot objects under this bridge */
339 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, 353 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
340 register_slot, bridge, NULL); 354 register_slot, bridge, NULL);
355 if (ACPI_FAILURE(status)) {
356 list_del(&bridge->list);
357 return;
358 }
341 359
342 /* install notify handler */ 360 /* install notify handler */
343 if (bridge->type != BRIDGE_TYPE_HOST) { 361 if (bridge->type != BRIDGE_TYPE_HOST) {
@@ -350,8 +368,6 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
350 err("failed to register interrupt notify handler\n"); 368 err("failed to register interrupt notify handler\n");
351 } 369 }
352 } 370 }
353
354 list_add(&bridge->list, &bridge_list);
355} 371}
356 372
357 373
@@ -555,6 +571,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
555 list_del(list); 571 list_del(list);
556 kfree(func); 572 kfree(func);
557 } 573 }
574 acpiphp_unregister_hotplug_slot(slot);
575 list_del(&slot->funcs);
558 kfree(slot); 576 kfree(slot);
559 slot = next; 577 slot = next;
560 } 578 }
@@ -1521,26 +1539,6 @@ static int acpiphp_for_each_slot(acpiphp_callback fn, void *data)
1521} 1539}
1522#endif 1540#endif
1523 1541
1524/* search matching slot from id */
1525struct acpiphp_slot *get_slot_from_id(int id)
1526{
1527 struct list_head *node;
1528 struct acpiphp_bridge *bridge;
1529 struct acpiphp_slot *slot;
1530
1531 list_for_each (node, &bridge_list) {
1532 bridge = (struct acpiphp_bridge *)node;
1533 for (slot = bridge->slots; slot; slot = slot->next)
1534 if (slot->id == id)
1535 return slot;
1536 }
1537
1538 /* should never happen! */
1539 err("%s: no object for id %d\n", __FUNCTION__, id);
1540 WARN_ON(1);
1541 return NULL;
1542}
1543
1544 1542
1545/** 1543/**
1546 * acpiphp_enable_slot - power on slot 1544 * acpiphp_enable_slot - power on slot