aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/fakephp.c39
1 files changed, 35 insertions, 4 deletions
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index d7a293e3faf5..94b640146d44 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -39,6 +39,7 @@
39#include <linux/init.h> 39#include <linux/init.h>
40#include <linux/string.h> 40#include <linux/string.h>
41#include <linux/slab.h> 41#include <linux/slab.h>
42#include <linux/workqueue.h>
42#include "../pci.h" 43#include "../pci.h"
43 44
44#if !defined(MODULE) 45#if !defined(MODULE)
@@ -63,10 +64,16 @@ struct dummy_slot {
63 struct list_head node; 64 struct list_head node;
64 struct hotplug_slot *slot; 65 struct hotplug_slot *slot;
65 struct pci_dev *dev; 66 struct pci_dev *dev;
67 struct work_struct remove_work;
68 unsigned long removed;
66}; 69};
67 70
68static int debug; 71static int debug;
69static LIST_HEAD(slot_list); 72static LIST_HEAD(slot_list);
73static struct workqueue_struct *dummyphp_wq;
74
75static void pci_rescan_worker(struct work_struct *work);
76static DECLARE_WORK(pci_rescan_work, pci_rescan_worker);
70 77
71static int enable_slot (struct hotplug_slot *slot); 78static int enable_slot (struct hotplug_slot *slot);
72static int disable_slot (struct hotplug_slot *slot); 79static int disable_slot (struct hotplug_slot *slot);
@@ -109,7 +116,7 @@ static int add_slot(struct pci_dev *dev)
109 slot->name = &dev->dev.bus_id[0]; 116 slot->name = &dev->dev.bus_id[0];
110 dbg("slot->name = %s\n", slot->name); 117 dbg("slot->name = %s\n", slot->name);
111 118
112 dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL); 119 dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL);
113 if (!dslot) 120 if (!dslot)
114 goto error_info; 121 goto error_info;
115 122
@@ -164,6 +171,14 @@ static void remove_slot(struct dummy_slot *dslot)
164 err("Problem unregistering a slot %s\n", dslot->slot->name); 171 err("Problem unregistering a slot %s\n", dslot->slot->name);
165} 172}
166 173
174/* called from the single-threaded workqueue handler to remove a slot */
175static void remove_slot_worker(struct work_struct *work)
176{
177 struct dummy_slot *dslot =
178 container_of(work, struct dummy_slot, remove_work);
179 remove_slot(dslot);
180}
181
167/** 182/**
168 * pci_rescan_slot - Rescan slot 183 * pci_rescan_slot - Rescan slot
169 * @temp: Device template. Should be set: bus and devfn. 184 * @temp: Device template. Should be set: bus and devfn.
@@ -267,11 +282,17 @@ static inline void pci_rescan(void) {
267 pci_rescan_buses(&pci_root_buses); 282 pci_rescan_buses(&pci_root_buses);
268} 283}
269 284
285/* called from the single-threaded workqueue handler to rescan all pci buses */
286static void pci_rescan_worker(struct work_struct *work)
287{
288 pci_rescan();
289}
270 290
271static int enable_slot(struct hotplug_slot *hotplug_slot) 291static int enable_slot(struct hotplug_slot *hotplug_slot)
272{ 292{
273 /* mis-use enable_slot for rescanning of the pci bus */ 293 /* mis-use enable_slot for rescanning of the pci bus */
274 pci_rescan(); 294 cancel_work_sync(&pci_rescan_work);
295 queue_work(dummyphp_wq, &pci_rescan_work);
275 return -ENODEV; 296 return -ENODEV;
276} 297}
277 298
@@ -306,6 +327,10 @@ static int disable_slot(struct hotplug_slot *slot)
306 err("Can't remove PCI devices with other PCI devices behind it yet.\n"); 327 err("Can't remove PCI devices with other PCI devices behind it yet.\n");
307 return -ENODEV; 328 return -ENODEV;
308 } 329 }
330 if (test_and_set_bit(0, &dslot->removed)) {
331 dbg("Slot already scheduled for removal\n");
332 return -ENODEV;
333 }
309 /* search for subfunctions and disable them first */ 334 /* search for subfunctions and disable them first */
310 if (!(dslot->dev->devfn & 7)) { 335 if (!(dslot->dev->devfn & 7)) {
311 for (func = 1; func < 8; func++) { 336 for (func = 1; func < 8; func++) {
@@ -328,8 +353,9 @@ static int disable_slot(struct hotplug_slot *slot)
328 /* remove the device from the pci core */ 353 /* remove the device from the pci core */
329 pci_remove_bus_device(dslot->dev); 354 pci_remove_bus_device(dslot->dev);
330 355
331 /* blow away this sysfs entry and other parts. */ 356 /* queue work item to blow away this sysfs entry and other parts. */
332 remove_slot(dslot); 357 INIT_WORK(&dslot->remove_work, remove_slot_worker);
358 queue_work(dummyphp_wq, &dslot->remove_work);
333 359
334 return 0; 360 return 0;
335} 361}
@@ -340,6 +366,7 @@ static void cleanup_slots (void)
340 struct list_head *next; 366 struct list_head *next;
341 struct dummy_slot *dslot; 367 struct dummy_slot *dslot;
342 368
369 destroy_workqueue(dummyphp_wq);
343 list_for_each_safe (tmp, next, &slot_list) { 370 list_for_each_safe (tmp, next, &slot_list) {
344 dslot = list_entry (tmp, struct dummy_slot, node); 371 dslot = list_entry (tmp, struct dummy_slot, node);
345 remove_slot(dslot); 372 remove_slot(dslot);
@@ -351,6 +378,10 @@ static int __init dummyphp_init(void)
351{ 378{
352 info(DRIVER_DESC "\n"); 379 info(DRIVER_DESC "\n");
353 380
381 dummyphp_wq = create_singlethread_workqueue(MY_NAME);
382 if (!dummyphp_wq)
383 return -ENOMEM;
384
354 return pci_scan_buses(); 385 return pci_scan_buses();
355} 386}
356 387