| From 576d28a7c73013717311cfcb514dbcae27c82eeb Mon Sep 17 00:00:00 2001 |
| From: Larry Finger <Larry.Finger@lwfinger.net> |
| Date: Thu, 6 Dec 2012 21:55:16 -0600 |
| Subject: b43legacy: Fix firmware loading when driver is built into the kernel |
| |
| From: Larry Finger <Larry.Finger@lwfinger.net> |
| |
| commit 576d28a7c73013717311cfcb514dbcae27c82eeb upstream. |
| |
| Recent versions of udev cause synchronous firmware loading from the |
| probe routine to fail because the request to user space times out. |
| The original fix for b43legacy (commit a3ea2c7) moved the firmware |
| load from the probe routine to a work queue, but it still used synchronous |
| firmware loading. This method is OK when b43legacy is built as a module; |
| however, it fails when the driver is compiled into the kernel. |
| |
| This version changes the code to load the initial firmware file |
| using request_firmware_nowait(). A completion event is used to |
| hold the work queue until that file is available. The remaining |
| firmware files are read synchronously. |
| |
| Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> |
| Signed-off-by: John W. Linville <linville@tuxdriver.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/net/wireless/b43legacy/b43legacy.h | 5 +++ |
| drivers/net/wireless/b43legacy/main.c | 37 ++++++++++++++++++++++++----- |
| 2 files changed, 36 insertions(+), 6 deletions(-) |
| |
| --- a/drivers/net/wireless/b43legacy/b43legacy.h |
| +++ b/drivers/net/wireless/b43legacy/b43legacy.h |
| @@ -13,6 +13,7 @@ |
| |
| #include <linux/ssb/ssb.h> |
| #include <linux/ssb/ssb_driver_chipcommon.h> |
| +#include <linux/completion.h> |
| |
| #include <net/mac80211.h> |
| |
| @@ -733,6 +734,10 @@ struct b43legacy_wldev { |
| |
| /* Firmware data */ |
| struct b43legacy_firmware fw; |
| + const struct firmware *fwp; /* needed to pass fw pointer */ |
| + |
| + /* completion struct for firmware loading */ |
| + struct completion fw_load_complete; |
| |
| /* Devicelist in struct b43legacy_wl (all 802.11 cores) */ |
| struct list_head list; |
| --- a/drivers/net/wireless/b43legacy/main.c |
| +++ b/drivers/net/wireless/b43legacy/main.c |
| @@ -1513,9 +1513,17 @@ static void b43legacy_print_fw_helptext( |
| "and download the correct firmware (version 3).\n"); |
| } |
| |
| +static void b43legacy_fw_cb(const struct firmware *firmware, void *context) |
| +{ |
| + struct b43legacy_wldev *dev = context; |
| + |
| + dev->fwp = firmware; |
| + complete(&dev->fw_load_complete); |
| +} |
| + |
| static int do_request_fw(struct b43legacy_wldev *dev, |
| const char *name, |
| - const struct firmware **fw) |
| + const struct firmware **fw, bool async) |
| { |
| char path[sizeof(modparam_fwpostfix) + 32]; |
| struct b43legacy_fw_header *hdr; |
| @@ -1528,7 +1536,24 @@ static int do_request_fw(struct b43legac |
| snprintf(path, ARRAY_SIZE(path), |
| "b43legacy%s/%s.fw", |
| modparam_fwpostfix, name); |
| - err = request_firmware(fw, path, dev->dev->dev); |
| + b43legacyinfo(dev->wl, "Loading firmware %s\n", path); |
| + if (async) { |
| + init_completion(&dev->fw_load_complete); |
| + err = request_firmware_nowait(THIS_MODULE, 1, path, |
| + dev->dev->dev, GFP_KERNEL, |
| + dev, b43legacy_fw_cb); |
| + if (err) { |
| + b43legacyerr(dev->wl, "Unable to load firmware\n"); |
| + return err; |
| + } |
| + /* stall here until fw ready */ |
| + wait_for_completion(&dev->fw_load_complete); |
| + if (!dev->fwp) |
| + err = -EINVAL; |
| + *fw = dev->fwp; |
| + } else { |
| + err = request_firmware(fw, path, dev->dev->dev); |
| + } |
| if (err) { |
| b43legacyerr(dev->wl, "Firmware file \"%s\" not found " |
| "or load failed.\n", path); |
| @@ -1580,7 +1605,7 @@ static void b43legacy_request_firmware(s |
| filename = "ucode4"; |
| else |
| filename = "ucode5"; |
| - err = do_request_fw(dev, filename, &fw->ucode); |
| + err = do_request_fw(dev, filename, &fw->ucode, true); |
| if (err) |
| goto err_load; |
| } |
| @@ -1589,7 +1614,7 @@ static void b43legacy_request_firmware(s |
| filename = "pcm4"; |
| else |
| filename = "pcm5"; |
| - err = do_request_fw(dev, filename, &fw->pcm); |
| + err = do_request_fw(dev, filename, &fw->pcm, false); |
| if (err) |
| goto err_load; |
| } |
| @@ -1607,7 +1632,7 @@ static void b43legacy_request_firmware(s |
| default: |
| goto err_no_initvals; |
| } |
| - err = do_request_fw(dev, filename, &fw->initvals); |
| + err = do_request_fw(dev, filename, &fw->initvals, false); |
| if (err) |
| goto err_load; |
| } |
| @@ -1627,7 +1652,7 @@ static void b43legacy_request_firmware(s |
| default: |
| goto err_no_initvals; |
| } |
| - err = do_request_fw(dev, filename, &fw->initvals_band); |
| + err = do_request_fw(dev, filename, &fw->initvals_band, false); |
| if (err) |
| goto err_load; |
| } |