aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@googlemail.com>2010-04-29 11:53:33 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-05-07 14:26:38 -0400
commit160b82420ab41f1e67fbf2e56dc587837ef39ce0 (patch)
treeac957e6495ce636c5181c792d822a6e60fb5921f /drivers
parent96ff56419504ac6a610ff1af42330e0423242e16 (diff)
ar9170: wait for asynchronous firmware loading
This patch fixes a regression introduced by the following patch: "ar9170: load firmware asynchronously" When we kick off a firmware loading request and then unbind, or disconnect the usb device right away, we get into trouble: > ------------[ cut here ]------------ > WARNING: at lib/kref.c:44 kref_get+0x1c/0x20() > Hardware name: 18666GU > Modules linked in: ar9170usb [...] > Pid: 6588, comm: firmware/ar9170 Not tainted 2.6.34-rc5-wl #43 > Call Trace: > [<c102b05e>] ? warn_slowpath_common+0x6e/0xb0 > [<c117c93c>] ? kref_get+0x1c/0x20 > [<c102b0b3>] ? warn_slowpath_null+0x13/0x20 > [<c117c93c>] ? kref_get+0x1c/0x20 > [<c117bb2f>] ? kobject_get+0xf/0x20 > [<c124d630>] ? get_device+0x10/0x20 > [<c124e5a0>] ? device_add+0x60/0x530 > [<c117b8b5>] ? kobject_init+0x25/0xa0 > [<c12569f9>] ? _request_firmware+0x139/0x3e0 > [<c1256cc0>] ? request_firmware_work_func+0x20/0x70 > [<c1256ca0>] ? request_firmware_work_func+0x0/0x70 > [<c103ff24>] ? kthread+0x74/0x80 > [<c103feb0>] ? kthread+0x0/0x80 > [<c1003136>] ? kernel_thread_helper+0x6/0x10 >---[ end trace 2d50bd818f64a1b7 ]--- - followed by a random Oops - Avoid that by waiting for the firmware loading to finish (whether successfully or not) before the unbind in ar9170_usb_disconnect. Reported-by: Johannes Berg <johannes@sipsolutions.net> Bug-fixed-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Christian Lamparter <chunkeey@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c11
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.h1
2 files changed, 12 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index 6b1cb706e410..24dc555f5ff1 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -726,12 +726,16 @@ static void ar9170_usb_firmware_failed(struct ar9170_usb *aru)
726{ 726{
727 struct device *parent = aru->udev->dev.parent; 727 struct device *parent = aru->udev->dev.parent;
728 728
729 complete(&aru->firmware_loading_complete);
730
729 /* unbind anything failed */ 731 /* unbind anything failed */
730 if (parent) 732 if (parent)
731 down(&parent->sem); 733 down(&parent->sem);
732 device_release_driver(&aru->udev->dev); 734 device_release_driver(&aru->udev->dev);
733 if (parent) 735 if (parent)
734 up(&parent->sem); 736 up(&parent->sem);
737
738 usb_put_dev(aru->udev);
735} 739}
736 740
737static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) 741static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context)
@@ -760,6 +764,8 @@ static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context)
760 if (err) 764 if (err)
761 goto err_unrx; 765 goto err_unrx;
762 766
767 complete(&aru->firmware_loading_complete);
768 usb_put_dev(aru->udev);
763 return; 769 return;
764 770
765 err_unrx: 771 err_unrx:
@@ -857,6 +863,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
857 init_usb_anchor(&aru->tx_pending); 863 init_usb_anchor(&aru->tx_pending);
858 init_usb_anchor(&aru->tx_submitted); 864 init_usb_anchor(&aru->tx_submitted);
859 init_completion(&aru->cmd_wait); 865 init_completion(&aru->cmd_wait);
866 init_completion(&aru->firmware_loading_complete);
860 spin_lock_init(&aru->tx_urb_lock); 867 spin_lock_init(&aru->tx_urb_lock);
861 868
862 aru->tx_pending_urbs = 0; 869 aru->tx_pending_urbs = 0;
@@ -876,6 +883,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
876 if (err) 883 if (err)
877 goto err_freehw; 884 goto err_freehw;
878 885
886 usb_get_dev(aru->udev);
879 return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw", 887 return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw",
880 &aru->udev->dev, GFP_KERNEL, aru, 888 &aru->udev->dev, GFP_KERNEL, aru,
881 ar9170_usb_firmware_step2); 889 ar9170_usb_firmware_step2);
@@ -895,6 +903,9 @@ static void ar9170_usb_disconnect(struct usb_interface *intf)
895 return; 903 return;
896 904
897 aru->common.state = AR9170_IDLE; 905 aru->common.state = AR9170_IDLE;
906
907 wait_for_completion(&aru->firmware_loading_complete);
908
898 ar9170_unregister(&aru->common); 909 ar9170_unregister(&aru->common);
899 ar9170_usb_cancel_urbs(aru); 910 ar9170_usb_cancel_urbs(aru);
900 911
diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h
index a2ce3b169ceb..919b06046eb3 100644
--- a/drivers/net/wireless/ath/ar9170/usb.h
+++ b/drivers/net/wireless/ath/ar9170/usb.h
@@ -71,6 +71,7 @@ struct ar9170_usb {
71 unsigned int tx_pending_urbs; 71 unsigned int tx_pending_urbs;
72 72
73 struct completion cmd_wait; 73 struct completion cmd_wait;
74 struct completion firmware_loading_complete;
74 int readlen; 75 int readlen;
75 u8 *readbuf; 76 u8 *readbuf;
76 77