Commit 1a712907 authored by Larry Finger's avatar Larry Finger Committed by Greg Kroah-Hartman

b43: Fix unload oops if firmware is not available

commit 0673effd upstream.

The asyncronous firmware load uses a completion struct to hold firmware
processing until the user-space routines are up and running. There is.
however, a problem in that the waiter is nevered canceled during teardown.
As a result, unloading the driver when firmware is not available causes an oops.

To be able to access the completion structure at teardown, it had to be moved
into the b43_wldev structure.

This patch also fixes a typo in a comment.
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent eeb405fd
...@@ -731,8 +731,6 @@ enum b43_firmware_file_type { ...@@ -731,8 +731,6 @@ enum b43_firmware_file_type {
struct b43_request_fw_context { struct b43_request_fw_context {
/* The device we are requesting the fw for. */ /* The device we are requesting the fw for. */
struct b43_wldev *dev; struct b43_wldev *dev;
/* a completion event structure needed if this call is asynchronous */
struct completion fw_load_complete;
/* a pointer to the firmware object */ /* a pointer to the firmware object */
const struct firmware *blob; const struct firmware *blob;
/* The type of firmware to request. */ /* The type of firmware to request. */
...@@ -809,6 +807,8 @@ enum { ...@@ -809,6 +807,8 @@ enum {
struct b43_wldev { struct b43_wldev {
struct b43_bus_dev *dev; struct b43_bus_dev *dev;
struct b43_wl *wl; struct b43_wl *wl;
/* a completion event structure needed if this call is asynchronous */
struct completion fw_load_complete;
/* The device initialization status. /* The device initialization status.
* Use b43_status() to query. */ * Use b43_status() to query. */
......
...@@ -2068,6 +2068,7 @@ void b43_do_release_fw(struct b43_firmware_file *fw) ...@@ -2068,6 +2068,7 @@ void b43_do_release_fw(struct b43_firmware_file *fw)
static void b43_release_firmware(struct b43_wldev *dev) static void b43_release_firmware(struct b43_wldev *dev)
{ {
complete(&dev->fw_load_complete);
b43_do_release_fw(&dev->fw.ucode); b43_do_release_fw(&dev->fw.ucode);
b43_do_release_fw(&dev->fw.pcm); b43_do_release_fw(&dev->fw.pcm);
b43_do_release_fw(&dev->fw.initvals); b43_do_release_fw(&dev->fw.initvals);
...@@ -2093,7 +2094,7 @@ static void b43_fw_cb(const struct firmware *firmware, void *context) ...@@ -2093,7 +2094,7 @@ static void b43_fw_cb(const struct firmware *firmware, void *context)
struct b43_request_fw_context *ctx = context; struct b43_request_fw_context *ctx = context;
ctx->blob = firmware; ctx->blob = firmware;
complete(&ctx->fw_load_complete); complete(&ctx->dev->fw_load_complete);
} }
int b43_do_request_fw(struct b43_request_fw_context *ctx, int b43_do_request_fw(struct b43_request_fw_context *ctx,
...@@ -2140,7 +2141,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, ...@@ -2140,7 +2141,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
} }
if (async) { if (async) {
/* do this part asynchronously */ /* do this part asynchronously */
init_completion(&ctx->fw_load_complete); init_completion(&ctx->dev->fw_load_complete);
err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname,
ctx->dev->dev->dev, GFP_KERNEL, ctx->dev->dev->dev, GFP_KERNEL,
ctx, b43_fw_cb); ctx, b43_fw_cb);
...@@ -2148,12 +2149,11 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, ...@@ -2148,12 +2149,11 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
pr_err("Unable to load firmware\n"); pr_err("Unable to load firmware\n");
return err; return err;
} }
/* stall here until fw ready */ wait_for_completion(&ctx->dev->fw_load_complete);
wait_for_completion(&ctx->fw_load_complete);
if (ctx->blob) if (ctx->blob)
goto fw_ready; goto fw_ready;
/* On some ARM systems, the async request will fail, but the next sync /* On some ARM systems, the async request will fail, but the next sync
* request works. For this reason, we dall through here * request works. For this reason, we fall through here
*/ */
} }
err = request_firmware(&ctx->blob, ctx->fwname, err = request_firmware(&ctx->blob, ctx->fwname,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment