aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@csr.com>2008-11-07 12:37:33 -0500
committerDavid Vrabel <david.vrabel@csr.com>2008-11-07 12:37:33 -0500
commit307ba6dd73254fe7d2ce27db64ffd90e1bb3c6c0 (patch)
tree535e10e6bd399c1f1d1f55a546e0c6aa92ba9dee
parentfec1a5932f16c0eb1b3f5ca2e18d81d860924088 (diff)
uwb: don't unbind the radio controller driver when resetting
Use pre_reset and post_reset methods to avoid unbinding the radio controller driver after a uwb_rc_reset_all() call. This avoids a deadlock in uwb_rc_rm() when waiting for the uwb event thread to stop. Signed-off-by: David Vrabel <david.vrabel@csr.com>
-rw-r--r--drivers/uwb/hwa-rc.c22
-rw-r--r--drivers/uwb/reset.c49
-rw-r--r--drivers/uwb/rsv.c29
-rw-r--r--drivers/uwb/umc-bus.c62
-rw-r--r--drivers/uwb/uwb-internal.h1
-rw-r--r--drivers/uwb/whc-rc.c30
-rw-r--r--include/linux/uwb.h2
-rw-r--r--include/linux/uwb/umc.h2
8 files changed, 155 insertions, 42 deletions
diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c
index 18009c99577d..158e98d08af9 100644
--- a/drivers/uwb/hwa-rc.c
+++ b/drivers/uwb/hwa-rc.c
@@ -881,6 +881,24 @@ static void hwarc_disconnect(struct usb_interface *iface)
881 uwb_rc_put(uwb_rc); /* when creating the device, refcount = 1 */ 881 uwb_rc_put(uwb_rc); /* when creating the device, refcount = 1 */
882} 882}
883 883
884static int hwarc_pre_reset(struct usb_interface *iface)
885{
886 struct hwarc *hwarc = usb_get_intfdata(iface);
887 struct uwb_rc *uwb_rc = hwarc->uwb_rc;
888
889 uwb_rc_pre_reset(uwb_rc);
890 return 0;
891}
892
893static int hwarc_post_reset(struct usb_interface *iface)
894{
895 struct hwarc *hwarc = usb_get_intfdata(iface);
896 struct uwb_rc *uwb_rc = hwarc->uwb_rc;
897
898 uwb_rc_post_reset(uwb_rc);
899 return 0;
900}
901
884/** USB device ID's that we handle */ 902/** USB device ID's that we handle */
885static struct usb_device_id hwarc_id_table[] = { 903static struct usb_device_id hwarc_id_table[] = {
886 /* D-Link DUB-1210 */ 904 /* D-Link DUB-1210 */
@@ -897,9 +915,11 @@ MODULE_DEVICE_TABLE(usb, hwarc_id_table);
897 915
898static struct usb_driver hwarc_driver = { 916static struct usb_driver hwarc_driver = {
899 .name = "hwa-rc", 917 .name = "hwa-rc",
918 .id_table = hwarc_id_table,
900 .probe = hwarc_probe, 919 .probe = hwarc_probe,
901 .disconnect = hwarc_disconnect, 920 .disconnect = hwarc_disconnect,
902 .id_table = hwarc_id_table, 921 .pre_reset = hwarc_pre_reset,
922 .post_reset = hwarc_post_reset,
903}; 923};
904 924
905static int __init hwarc_driver_init(void) 925static int __init hwarc_driver_init(void)
diff --git a/drivers/uwb/reset.c b/drivers/uwb/reset.c
index 8de856fa7958..e39b32099af3 100644
--- a/drivers/uwb/reset.c
+++ b/drivers/uwb/reset.c
@@ -323,17 +323,16 @@ int uwbd_msg_handle_reset(struct uwb_event *evt)
323 struct uwb_rc *rc = evt->rc; 323 struct uwb_rc *rc = evt->rc;
324 int ret; 324 int ret;
325 325
326 /* Need to prevent the RC hardware module going away while in
327 the rc->reset() call. */
328 if (!try_module_get(rc->owner))
329 return 0;
330
331 dev_info(&rc->uwb_dev.dev, "resetting radio controller\n"); 326 dev_info(&rc->uwb_dev.dev, "resetting radio controller\n");
332 ret = rc->reset(rc); 327 ret = rc->reset(rc);
333 if (ret) 328 if (ret) {
334 dev_err(&rc->uwb_dev.dev, "failed to reset hardware: %d\n", ret); 329 dev_err(&rc->uwb_dev.dev, "failed to reset hardware: %d\n", ret);
335 330 goto error;
336 module_put(rc->owner); 331 }
332 return 0;
333error:
334 /* Nothing can be done except try the reset again. */
335 uwb_rc_reset_all(rc);
337 return ret; 336 return ret;
338} 337}
339 338
@@ -360,3 +359,37 @@ void uwb_rc_reset_all(struct uwb_rc *rc)
360 uwbd_event_queue(evt); 359 uwbd_event_queue(evt);
361} 360}
362EXPORT_SYMBOL_GPL(uwb_rc_reset_all); 361EXPORT_SYMBOL_GPL(uwb_rc_reset_all);
362
363void uwb_rc_pre_reset(struct uwb_rc *rc)
364{
365 rc->stop(rc);
366 uwbd_flush(rc);
367
368 mutex_lock(&rc->uwb_dev.mutex);
369 rc->beaconing = -1;
370 rc->scanning = -1;
371 mutex_unlock(&rc->uwb_dev.mutex);
372
373 uwb_rsv_remove_all(rc);
374}
375EXPORT_SYMBOL_GPL(uwb_rc_pre_reset);
376
377void uwb_rc_post_reset(struct uwb_rc *rc)
378{
379 int ret;
380
381 ret = rc->start(rc);
382 if (ret)
383 goto error;
384 ret = uwb_rc_mac_addr_set(rc, &rc->uwb_dev.mac_addr);
385 if (ret)
386 goto error;
387 ret = uwb_rc_dev_addr_set(rc, &rc->uwb_dev.dev_addr);
388 if (ret)
389 goto error;
390 return;
391error:
392 /* Nothing can be done except try the reset again. */
393 uwb_rc_reset_all(rc);
394}
395EXPORT_SYMBOL_GPL(uwb_rc_post_reset);
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c
index ce0094657d3d..3d76efe26acc 100644
--- a/drivers/uwb/rsv.c
+++ b/drivers/uwb/rsv.c
@@ -659,6 +659,25 @@ static void uwb_rsv_timer(unsigned long arg)
659 uwb_rsv_sched_update(rsv->rc); 659 uwb_rsv_sched_update(rsv->rc);
660} 660}
661 661
662/**
663 * uwb_rsv_remove_all - remove all reservations
664 * @rc: the radio controller
665 *
666 * A DRP IE update is not done.
667 */
668void uwb_rsv_remove_all(struct uwb_rc *rc)
669{
670 struct uwb_rsv *rsv, *t;
671
672 mutex_lock(&rc->rsvs_mutex);
673 list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
674 uwb_rsv_remove(rsv);
675 }
676 mutex_unlock(&rc->rsvs_mutex);
677
678 cancel_work_sync(&rc->rsv_update_work);
679}
680
662void uwb_rsv_init(struct uwb_rc *rc) 681void uwb_rsv_init(struct uwb_rc *rc)
663{ 682{
664 INIT_LIST_HEAD(&rc->reservations); 683 INIT_LIST_HEAD(&rc->reservations);
@@ -682,14 +701,6 @@ int uwb_rsv_setup(struct uwb_rc *rc)
682 701
683void uwb_rsv_cleanup(struct uwb_rc *rc) 702void uwb_rsv_cleanup(struct uwb_rc *rc)
684{ 703{
685 struct uwb_rsv *rsv, *t; 704 uwb_rsv_remove_all(rc);
686
687 mutex_lock(&rc->rsvs_mutex);
688 list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
689 uwb_rsv_remove(rsv);
690 }
691 mutex_unlock(&rc->rsvs_mutex);
692
693 cancel_work_sync(&rc->rsv_update_work);
694 destroy_workqueue(rc->rsv_workq); 705 destroy_workqueue(rc->rsv_workq);
695} 706}
diff --git a/drivers/uwb/umc-bus.c b/drivers/uwb/umc-bus.c
index 2d8d62d9f53e..5ad36164c13b 100644
--- a/drivers/uwb/umc-bus.c
+++ b/drivers/uwb/umc-bus.c
@@ -11,23 +11,48 @@
11#include <linux/uwb/umc.h> 11#include <linux/uwb/umc.h>
12#include <linux/pci.h> 12#include <linux/pci.h>
13 13
14static int umc_bus_unbind_helper(struct device *dev, void *data) 14static int umc_bus_pre_reset_helper(struct device *dev, void *data)
15{ 15{
16 struct device *parent = data; 16 int ret = 0;
17 17
18 if (dev->parent == parent && dev->driver) 18 if (dev->driver) {
19 device_release_driver(dev); 19 struct umc_dev *umc = to_umc_dev(dev);
20 return 0; 20 struct umc_driver *umc_drv = to_umc_driver(dev->driver);
21
22 if (umc_drv->pre_reset)
23 ret = umc_drv->pre_reset(umc);
24 else
25 device_release_driver(dev);
26 }
27 return ret;
28}
29
30static int umc_bus_post_reset_helper(struct device *dev, void *data)
31{
32 int ret = 0;
33
34 if (dev->driver) {
35 struct umc_dev *umc = to_umc_dev(dev);
36 struct umc_driver *umc_drv = to_umc_driver(dev->driver);
37
38 if (umc_drv->post_reset)
39 ret = umc_drv->post_reset(umc);
40 } else
41 ret = device_attach(dev);
42
43 return ret;
21} 44}
22 45
23/** 46/**
24 * umc_controller_reset - reset the whole UMC controller 47 * umc_controller_reset - reset the whole UMC controller
25 * @umc: the UMC device for the radio controller. 48 * @umc: the UMC device for the radio controller.
26 * 49 *
27 * Drivers will be unbound from all UMC devices belonging to the 50 * Drivers or all capabilities of the controller will have their
28 * controller and then the radio controller will be rebound. The 51 * pre_reset methods called or be unbound from their device. Then all
29 * radio controller is expected to do a full hardware reset when it is 52 * post_reset methods will be called or the drivers will be rebound.
30 * probed. 53 *
54 * Radio controllers must provide pre_reset and post_reset methods and
55 * reset the hardware in their start method.
31 * 56 *
32 * If this is called while a probe() or remove() is in progress it 57 * If this is called while a probe() or remove() is in progress it
33 * will return -EAGAIN and not perform the reset. 58 * will return -EAGAIN and not perform the reset.
@@ -35,14 +60,13 @@ static int umc_bus_unbind_helper(struct device *dev, void *data)
35int umc_controller_reset(struct umc_dev *umc) 60int umc_controller_reset(struct umc_dev *umc)
36{ 61{
37 struct device *parent = umc->dev.parent; 62 struct device *parent = umc->dev.parent;
38 int ret; 63 int ret = 0;
39 64
40 if (down_trylock(&parent->sem)) 65 if(down_trylock(&parent->sem))
41 return -EAGAIN; 66 return -EAGAIN;
42 bus_for_each_dev(&umc_bus_type, NULL, parent, umc_bus_unbind_helper); 67 ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper);
43 ret = device_attach(&umc->dev); 68 if (ret >= 0)
44 if (ret == 1) 69 device_for_each_child(parent, parent, umc_bus_post_reset_helper);
45 ret = 0;
46 up(&parent->sem); 70 up(&parent->sem);
47 71
48 return ret; 72 return ret;
@@ -75,10 +99,10 @@ static int umc_bus_rescan_helper(struct device *dev, void *data)
75 if (!dev->driver) 99 if (!dev->driver)
76 ret = device_attach(dev); 100 ret = device_attach(dev);
77 101
78 return ret < 0 ? ret : 0; 102 return ret;
79} 103}
80 104
81static void umc_bus_rescan(void) 105static void umc_bus_rescan(struct device *parent)
82{ 106{
83 int err; 107 int err;
84 108
@@ -86,7 +110,7 @@ static void umc_bus_rescan(void)
86 * We can't use bus_rescan_devices() here as it deadlocks when 110 * We can't use bus_rescan_devices() here as it deadlocks when
87 * it tries to retake the dev->parent semaphore. 111 * it tries to retake the dev->parent semaphore.
88 */ 112 */
89 err = bus_for_each_dev(&umc_bus_type, NULL, NULL, umc_bus_rescan_helper); 113 err = device_for_each_child(parent, NULL, umc_bus_rescan_helper);
90 if (err < 0) 114 if (err < 0)
91 printk(KERN_WARNING "%s: rescan of bus failed: %d\n", 115 printk(KERN_WARNING "%s: rescan of bus failed: %d\n",
92 KBUILD_MODNAME, err); 116 KBUILD_MODNAME, err);
@@ -120,7 +144,7 @@ static int umc_device_probe(struct device *dev)
120 if (err) 144 if (err)
121 put_device(dev); 145 put_device(dev);
122 else 146 else
123 umc_bus_rescan(); 147 umc_bus_rescan(dev->parent);
124 148
125 return err; 149 return err;
126} 150}
diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h
index 4c2449679978..af95541dabcd 100644
--- a/drivers/uwb/uwb-internal.h
+++ b/drivers/uwb/uwb-internal.h
@@ -248,6 +248,7 @@ extern struct device_attribute dev_attr_scan;
248void uwb_rsv_init(struct uwb_rc *rc); 248void uwb_rsv_init(struct uwb_rc *rc);
249int uwb_rsv_setup(struct uwb_rc *rc); 249int uwb_rsv_setup(struct uwb_rc *rc);
250void uwb_rsv_cleanup(struct uwb_rc *rc); 250void uwb_rsv_cleanup(struct uwb_rc *rc);
251void uwb_rsv_remove_all(struct uwb_rc *rc);
251 252
252void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state); 253void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state);
253void uwb_rsv_remove(struct uwb_rsv *rsv); 254void uwb_rsv_remove(struct uwb_rsv *rsv);
diff --git a/drivers/uwb/whc-rc.c b/drivers/uwb/whc-rc.c
index 6c454eadd307..e0d66938ccd8 100644
--- a/drivers/uwb/whc-rc.c
+++ b/drivers/uwb/whc-rc.c
@@ -394,7 +394,7 @@ void whcrc_stop_rc(struct uwb_rc *rc)
394 394
395 le_writel(0, whcrc->rc_base + URCCMD); 395 le_writel(0, whcrc->rc_base + URCCMD);
396 whci_wait_for(&umc_dev->dev, whcrc->rc_base + URCSTS, 396 whci_wait_for(&umc_dev->dev, whcrc->rc_base + URCSTS,
397 URCSTS_HALTED, 0, 40, "URCSTS.HALTED"); 397 URCSTS_HALTED, URCSTS_HALTED, 100, "URCSTS.HALTED");
398} 398}
399 399
400static void whcrc_init(struct whcrc *whcrc) 400static void whcrc_init(struct whcrc *whcrc)
@@ -488,6 +488,24 @@ static void whcrc_remove(struct umc_dev *umc_dev)
488 d_printf(1, &umc_dev->dev, "freed whcrc %p\n", whcrc); 488 d_printf(1, &umc_dev->dev, "freed whcrc %p\n", whcrc);
489} 489}
490 490
491static int whcrc_pre_reset(struct umc_dev *umc)
492{
493 struct whcrc *whcrc = umc_get_drvdata(umc);
494 struct uwb_rc *uwb_rc = whcrc->uwb_rc;
495
496 uwb_rc_pre_reset(uwb_rc);
497 return 0;
498}
499
500static int whcrc_post_reset(struct umc_dev *umc)
501{
502 struct whcrc *whcrc = umc_get_drvdata(umc);
503 struct uwb_rc *uwb_rc = whcrc->uwb_rc;
504
505 uwb_rc_post_reset(uwb_rc);
506 return 0;
507}
508
491/* PCI device ID's that we handle [so it gets loaded] */ 509/* PCI device ID's that we handle [so it gets loaded] */
492static struct pci_device_id whcrc_id_table[] = { 510static struct pci_device_id whcrc_id_table[] = {
493 { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) }, 511 { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
@@ -496,10 +514,12 @@ static struct pci_device_id whcrc_id_table[] = {
496MODULE_DEVICE_TABLE(pci, whcrc_id_table); 514MODULE_DEVICE_TABLE(pci, whcrc_id_table);
497 515
498static struct umc_driver whcrc_driver = { 516static struct umc_driver whcrc_driver = {
499 .name = "whc-rc", 517 .name = "whc-rc",
500 .cap_id = UMC_CAP_ID_WHCI_RC, 518 .cap_id = UMC_CAP_ID_WHCI_RC,
501 .probe = whcrc_probe, 519 .probe = whcrc_probe,
502 .remove = whcrc_remove, 520 .remove = whcrc_remove,
521 .pre_reset = whcrc_pre_reset,
522 .post_reset = whcrc_post_reset,
503}; 523};
504 524
505static int __init whcrc_driver_init(void) 525static int __init whcrc_driver_init(void)
diff --git a/include/linux/uwb.h b/include/linux/uwb.h
index 881f0c5b6d28..c4854848999d 100644
--- a/include/linux/uwb.h
+++ b/include/linux/uwb.h
@@ -540,6 +540,8 @@ void uwb_rc_rm(struct uwb_rc *);
540void uwb_rc_neh_grok(struct uwb_rc *, void *, size_t); 540void uwb_rc_neh_grok(struct uwb_rc *, void *, size_t);
541void uwb_rc_neh_error(struct uwb_rc *, int); 541void uwb_rc_neh_error(struct uwb_rc *, int);
542void uwb_rc_reset_all(struct uwb_rc *rc); 542void uwb_rc_reset_all(struct uwb_rc *rc);
543void uwb_rc_pre_reset(struct uwb_rc *rc);
544void uwb_rc_post_reset(struct uwb_rc *rc);
543 545
544/** 546/**
545 * uwb_rsv_is_owner - is the owner of this reservation the RC? 547 * uwb_rsv_is_owner - is the owner of this reservation the RC?
diff --git a/include/linux/uwb/umc.h b/include/linux/uwb/umc.h
index 36a39e34f8d7..4b4fc0f43855 100644
--- a/include/linux/uwb/umc.h
+++ b/include/linux/uwb/umc.h
@@ -89,6 +89,8 @@ struct umc_driver {
89 void (*remove)(struct umc_dev *); 89 void (*remove)(struct umc_dev *);
90 int (*suspend)(struct umc_dev *, pm_message_t state); 90 int (*suspend)(struct umc_dev *, pm_message_t state);
91 int (*resume)(struct umc_dev *); 91 int (*resume)(struct umc_dev *);
92 int (*pre_reset)(struct umc_dev *);
93 int (*post_reset)(struct umc_dev *);
92 94
93 struct device_driver driver; 95 struct device_driver driver;
94}; 96};