ar9170: load firmware asynchronously

This converts ar9170 to load firmware asynchronously
out of ->probe() and only register with mac80211 when
all firmware has been loaded successfully. If, on the
other hand, any firmware fails to load, it will now
unbind from the device.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Johannes Berg 2009-12-23 13:15:30 +01:00 committed by John W. Linville
parent 6e93d7195e
commit 535765179f
3 changed files with 111 additions and 70 deletions

View file

@ -166,6 +166,7 @@ struct ar9170 {
struct ath_common common;
struct mutex mutex;
enum ar9170_device_state state;
bool registered;
unsigned long bad_hw_nagger;
int (*open)(struct ar9170 *);

View file

@ -2701,7 +2701,8 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev)
dev_info(pdev, "Atheros AR9170 is registered as '%s'\n",
wiphy_name(ar->hw->wiphy));
return err;
ar->registered = true;
return 0;
err_unreg:
ieee80211_unregister_hw(ar->hw);
@ -2712,11 +2713,14 @@ err_out:
void ar9170_unregister(struct ar9170 *ar)
{
if (ar->registered) {
#ifdef CONFIG_AR9170_LEDS
ar9170_unregister_leds(ar);
ar9170_unregister_leds(ar);
#endif /* CONFIG_AR9170_LEDS */
kfree_skb(ar->rx_failover);
ieee80211_unregister_hw(ar->hw);
}
kfree_skb(ar->rx_failover);
mutex_destroy(&ar->mutex);
}

View file

@ -582,43 +582,6 @@ static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data,
return 0;
}
static int ar9170_usb_request_firmware(struct ar9170_usb *aru)
{
int err = 0;
err = request_firmware(&aru->firmware, "ar9170.fw",
&aru->udev->dev);
if (!err) {
aru->init_values = NULL;
return 0;
}
if (aru->req_one_stage_fw) {
dev_err(&aru->udev->dev, "ar9170.fw firmware file "
"not found and is required for this device\n");
return -EINVAL;
}
dev_err(&aru->udev->dev, "ar9170.fw firmware file "
"not found, trying old firmware...\n");
err = request_firmware(&aru->init_values, "ar9170-1.fw",
&aru->udev->dev);
if (err) {
dev_err(&aru->udev->dev, "file with init values not found.\n");
return err;
}
err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev);
if (err) {
release_firmware(aru->init_values);
dev_err(&aru->udev->dev, "firmware file not found.\n");
return err;
}
return err;
}
static int ar9170_usb_reset(struct ar9170_usb *aru)
{
int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING);
@ -757,6 +720,103 @@ err_out:
return err;
}
static void ar9170_usb_firmware_failed(struct ar9170_usb *aru)
{
struct device *parent = aru->udev->dev.parent;
/* unbind anything failed */
if (parent)
down(&parent->sem);
device_release_driver(&aru->udev->dev);
if (parent)
up(&parent->sem);
}
static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context)
{
struct ar9170_usb *aru = context;
int err;
aru->firmware = fw;
if (!fw) {
dev_err(&aru->udev->dev, "firmware file not found.\n");
goto err_freefw;
}
err = ar9170_usb_init_device(aru);
if (err)
goto err_freefw;
err = ar9170_usb_open(&aru->common);
if (err)
goto err_unrx;
err = ar9170_register(&aru->common, &aru->udev->dev);
ar9170_usb_stop(&aru->common);
if (err)
goto err_unrx;
return;
err_unrx:
ar9170_usb_cancel_urbs(aru);
err_freefw:
ar9170_usb_firmware_failed(aru);
}
static void ar9170_usb_firmware_inits(const struct firmware *fw,
void *context)
{
struct ar9170_usb *aru = context;
int err;
if (!fw) {
dev_err(&aru->udev->dev, "file with init values not found.\n");
ar9170_usb_firmware_failed(aru);
return;
}
aru->init_values = fw;
/* ok so we have the init values -- get code for two-stage */
err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw",
&aru->udev->dev, GFP_KERNEL, aru,
ar9170_usb_firmware_finish);
if (err)
ar9170_usb_firmware_failed(aru);
}
static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context)
{
struct ar9170_usb *aru = context;
int err;
if (fw) {
ar9170_usb_firmware_finish(fw, context);
return;
}
if (aru->req_one_stage_fw) {
dev_err(&aru->udev->dev, "ar9170.fw firmware file "
"not found and is required for this device\n");
ar9170_usb_firmware_failed(aru);
return;
}
dev_err(&aru->udev->dev, "ar9170.fw firmware file "
"not found, trying old firmware...\n");
err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw",
&aru->udev->dev, GFP_KERNEL, aru,
ar9170_usb_firmware_inits);
if (err)
ar9170_usb_firmware_failed(aru);
}
static bool ar9170_requires_one_stage(const struct usb_device_id *id)
{
if (!id->driver_info)
@ -814,33 +874,9 @@ static int ar9170_usb_probe(struct usb_interface *intf,
if (err)
goto err_freehw;
err = ar9170_usb_request_firmware(aru);
if (err)
goto err_freehw;
err = ar9170_usb_init_device(aru);
if (err)
goto err_freefw;
err = ar9170_usb_open(ar);
if (err)
goto err_unrx;
err = ar9170_register(ar, &udev->dev);
ar9170_usb_stop(ar);
if (err)
goto err_unrx;
return 0;
err_unrx:
ar9170_usb_cancel_urbs(aru);
err_freefw:
release_firmware(aru->init_values);
release_firmware(aru->firmware);
return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw",
&aru->udev->dev, GFP_KERNEL, aru,
ar9170_usb_firmware_step2);
err_freehw:
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);
@ -860,12 +896,12 @@ static void ar9170_usb_disconnect(struct usb_interface *intf)
ar9170_unregister(&aru->common);
ar9170_usb_cancel_urbs(aru);
release_firmware(aru->init_values);
release_firmware(aru->firmware);
usb_put_dev(aru->udev);
usb_set_intfdata(intf, NULL);
ieee80211_free_hw(aru->common.hw);
release_firmware(aru->init_values);
release_firmware(aru->firmware);
}
#ifdef CONFIG_PM