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:
Christian Lamparter 2010-04-29 17:53:33 +02:00 committed by John W. Linville
parent 96ff564195
commit 160b82420a
2 changed files with 12 additions and 0 deletions

View file

@ -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);

View file

@ -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;