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>
This commit is contained in:
parent
96ff564195
commit
160b82420a
2 changed files with 12 additions and 0 deletions
|
@ -726,12 +726,16 @@ static void ar9170_usb_firmware_failed(struct ar9170_usb *aru)
|
|||
{
|
||||
struct device *parent = aru->udev->dev.parent;
|
||||
|
||||
complete(&aru->firmware_loading_complete);
|
||||
|
||||
/* unbind anything failed */
|
||||
if (parent)
|
||||
down(&parent->sem);
|
||||
device_release_driver(&aru->udev->dev);
|
||||
if (parent)
|
||||
up(&parent->sem);
|
||||
|
||||
usb_put_dev(aru->udev);
|
||||
}
|
||||
|
||||
static 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)
|
|||
if (err)
|
||||
goto err_unrx;
|
||||
|
||||
complete(&aru->firmware_loading_complete);
|
||||
usb_put_dev(aru->udev);
|
||||
return;
|
||||
|
||||
err_unrx:
|
||||
|
@ -857,6 +863,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
|
|||
init_usb_anchor(&aru->tx_pending);
|
||||
init_usb_anchor(&aru->tx_submitted);
|
||||
init_completion(&aru->cmd_wait);
|
||||
init_completion(&aru->firmware_loading_complete);
|
||||
spin_lock_init(&aru->tx_urb_lock);
|
||||
|
||||
aru->tx_pending_urbs = 0;
|
||||
|
@ -876,6 +883,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
|
|||
if (err)
|
||||
goto err_freehw;
|
||||
|
||||
usb_get_dev(aru->udev);
|
||||
return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw",
|
||||
&aru->udev->dev, GFP_KERNEL, aru,
|
||||
ar9170_usb_firmware_step2);
|
||||
|
@ -895,6 +903,9 @@ static void ar9170_usb_disconnect(struct usb_interface *intf)
|
|||
return;
|
||||
|
||||
aru->common.state = AR9170_IDLE;
|
||||
|
||||
wait_for_completion(&aru->firmware_loading_complete);
|
||||
|
||||
ar9170_unregister(&aru->common);
|
||||
ar9170_usb_cancel_urbs(aru);
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ struct ar9170_usb {
|
|||
unsigned int tx_pending_urbs;
|
||||
|
||||
struct completion cmd_wait;
|
||||
struct completion firmware_loading_complete;
|
||||
int readlen;
|
||||
u8 *readbuf;
|
||||
|
||||
|
|
Loading…
Reference in a new issue