b43: Load firmware from a work queue and not from the probe routine

Recent changes in udev are causing problems for drivers that load firmware
from the probe routine. As b43 has such a structure, it must be changed.
As this driver loads more than 1 firmware file, changing to the asynchronous routine
request_firmware_nowait() would be complicated. In this implementation, the probe
routine starts a queue that calls the firmware loading routines.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Larry Finger 2012-03-08 22:27:46 -06:00 committed by John W. Linville
parent a3ea2c76b1
commit 6b6fa5868e
2 changed files with 35 additions and 27 deletions

View File

@ -932,6 +932,9 @@ struct b43_wl {
/* Flag that implement the queues stopping. */
bool tx_queue_stopped[B43_QOS_QUEUE_NUM];
/* firmware loading work */
struct work_struct firmware_load;
/* The device LEDs. */
struct b43_leds leds;

View File

@ -2390,8 +2390,14 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
return err;
}
static int b43_request_firmware(struct b43_wldev *dev)
static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl);
static void b43_one_core_detach(struct b43_bus_dev *dev);
static void b43_request_firmware(struct work_struct *work)
{
struct b43_wl *wl = container_of(work,
struct b43_wl, firmware_load);
struct b43_wldev *dev = wl->current_dev;
struct b43_request_fw_context *ctx;
unsigned int i;
int err;
@ -2399,23 +2405,23 @@ static int b43_request_firmware(struct b43_wldev *dev)
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
return;
ctx->dev = dev;
ctx->req_type = B43_FWTYPE_PROPRIETARY;
err = b43_try_request_fw(ctx);
if (!err)
goto out; /* Successfully loaded it. */
err = ctx->fatal_failure;
if (err)
goto start_ieee80211; /* Successfully loaded it. */
/* Was fw version known? */
if (ctx->fatal_failure)
goto out;
/* proprietary fw not found, try open source */
ctx->req_type = B43_FWTYPE_OPENSOURCE;
err = b43_try_request_fw(ctx);
if (!err)
goto out; /* Successfully loaded it. */
err = ctx->fatal_failure;
if (err)
goto start_ieee80211; /* Successfully loaded it. */
if(ctx->fatal_failure)
goto out;
/* Could not find a usable firmware. Print the errors. */
@ -2425,11 +2431,20 @@ static int b43_request_firmware(struct b43_wldev *dev)
b43err(dev->wl, errmsg);
}
b43_print_fw_helptext(dev->wl, 1);
err = -ENOENT;
goto out;
start_ieee80211:
err = ieee80211_register_hw(wl->hw);
if (err)
goto err_one_core_detach;
b43_leds_register(wl->current_dev);
goto out;
err_one_core_detach:
b43_one_core_detach(dev->dev);
out:
kfree(ctx);
return err;
}
static int b43_upload_microcode(struct b43_wldev *dev)
@ -3023,9 +3038,6 @@ static int b43_chip_init(struct b43_wldev *dev)
macctl |= B43_MACCTL_INFRA;
b43_write32(dev, B43_MMIO_MACCTL, macctl);
err = b43_request_firmware(dev);
if (err)
goto out;
err = b43_upload_microcode(dev);
if (err)
goto out; /* firmware is released later */
@ -4155,6 +4167,7 @@ static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev)
mutex_unlock(&wl->mutex);
cancel_delayed_work_sync(&dev->periodic_work);
cancel_work_sync(&wl->tx_work);
cancel_work_sync(&wl->firmware_load);
mutex_lock(&wl->mutex);
dev = wl->current_dev;
if (!dev || b43_status(dev) < B43_STAT_STARTED) {
@ -5314,16 +5327,13 @@ static int b43_bcma_probe(struct bcma_device *core)
if (err)
goto bcma_err_wireless_exit;
err = ieee80211_register_hw(wl->hw);
if (err)
goto bcma_err_one_core_detach;
b43_leds_register(wl->current_dev);
/* setup and start work to load firmware */
INIT_WORK(&wl->firmware_load, b43_request_firmware);
schedule_work(&wl->firmware_load);
bcma_out:
return err;
bcma_err_one_core_detach:
b43_one_core_detach(dev);
bcma_err_wireless_exit:
ieee80211_free_hw(wl->hw);
return err;
@ -5390,18 +5400,13 @@ int b43_ssb_probe(struct ssb_device *sdev, const struct ssb_device_id *id)
if (err)
goto err_wireless_exit;
if (first) {
err = ieee80211_register_hw(wl->hw);
if (err)
goto err_one_core_detach;
b43_leds_register(wl->current_dev);
}
/* setup and start work to load firmware */
INIT_WORK(&wl->firmware_load, b43_request_firmware);
schedule_work(&wl->firmware_load);
out:
return err;
err_one_core_detach:
b43_one_core_detach(dev);
err_wireless_exit:
if (first)
b43_wireless_exit(dev, wl);