diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2014-01-12 16:11:38 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-01-13 14:50:02 -0500 |
commit | 0673effd41dba323d6a280ef37b5ef29f3f5a653 (patch) | |
tree | a77566c99cb389a3b41584431041312cbfc4104e /drivers/net/wireless | |
parent | 09164043f63c947a49797750a09ca1cd7c31108e (diff) |
b43: Fix unload oops if firmware is not available
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: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Stable <stable@vger.kernel.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/b43/b43.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.c | 10 |
2 files changed, 7 insertions, 7 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 7f3d461f7e8d..54376fddfaf9 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -731,8 +731,6 @@ enum b43_firmware_file_type { | |||
731 | struct b43_request_fw_context { | 731 | struct b43_request_fw_context { |
732 | /* The device we are requesting the fw for. */ | 732 | /* The device we are requesting the fw for. */ |
733 | struct b43_wldev *dev; | 733 | struct b43_wldev *dev; |
734 | /* a completion event structure needed if this call is asynchronous */ | ||
735 | struct completion fw_load_complete; | ||
736 | /* a pointer to the firmware object */ | 734 | /* a pointer to the firmware object */ |
737 | const struct firmware *blob; | 735 | const struct firmware *blob; |
738 | /* The type of firmware to request. */ | 736 | /* The type of firmware to request. */ |
@@ -809,6 +807,8 @@ enum { | |||
809 | struct b43_wldev { | 807 | struct b43_wldev { |
810 | struct b43_bus_dev *dev; | 808 | struct b43_bus_dev *dev; |
811 | struct b43_wl *wl; | 809 | struct b43_wl *wl; |
810 | /* a completion event structure needed if this call is asynchronous */ | ||
811 | struct completion fw_load_complete; | ||
812 | 812 | ||
813 | /* The device initialization status. | 813 | /* The device initialization status. |
814 | * Use b43_status() to query. */ | 814 | * Use b43_status() to query. */ |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 86b2030055d2..c75237eb55a1 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -2070,6 +2070,7 @@ void b43_do_release_fw(struct b43_firmware_file *fw) | |||
2070 | 2070 | ||
2071 | static void b43_release_firmware(struct b43_wldev *dev) | 2071 | static void b43_release_firmware(struct b43_wldev *dev) |
2072 | { | 2072 | { |
2073 | complete(&dev->fw_load_complete); | ||
2073 | b43_do_release_fw(&dev->fw.ucode); | 2074 | b43_do_release_fw(&dev->fw.ucode); |
2074 | b43_do_release_fw(&dev->fw.pcm); | 2075 | b43_do_release_fw(&dev->fw.pcm); |
2075 | b43_do_release_fw(&dev->fw.initvals); | 2076 | b43_do_release_fw(&dev->fw.initvals); |
@@ -2095,7 +2096,7 @@ static void b43_fw_cb(const struct firmware *firmware, void *context) | |||
2095 | struct b43_request_fw_context *ctx = context; | 2096 | struct b43_request_fw_context *ctx = context; |
2096 | 2097 | ||
2097 | ctx->blob = firmware; | 2098 | ctx->blob = firmware; |
2098 | complete(&ctx->fw_load_complete); | 2099 | complete(&ctx->dev->fw_load_complete); |
2099 | } | 2100 | } |
2100 | 2101 | ||
2101 | int b43_do_request_fw(struct b43_request_fw_context *ctx, | 2102 | int b43_do_request_fw(struct b43_request_fw_context *ctx, |
@@ -2142,7 +2143,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, | |||
2142 | } | 2143 | } |
2143 | if (async) { | 2144 | if (async) { |
2144 | /* do this part asynchronously */ | 2145 | /* do this part asynchronously */ |
2145 | init_completion(&ctx->fw_load_complete); | 2146 | init_completion(&ctx->dev->fw_load_complete); |
2146 | err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, | 2147 | err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, |
2147 | ctx->dev->dev->dev, GFP_KERNEL, | 2148 | ctx->dev->dev->dev, GFP_KERNEL, |
2148 | ctx, b43_fw_cb); | 2149 | ctx, b43_fw_cb); |
@@ -2150,12 +2151,11 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, | |||
2150 | pr_err("Unable to load firmware\n"); | 2151 | pr_err("Unable to load firmware\n"); |
2151 | return err; | 2152 | return err; |
2152 | } | 2153 | } |
2153 | /* stall here until fw ready */ | 2154 | wait_for_completion(&ctx->dev->fw_load_complete); |
2154 | wait_for_completion(&ctx->fw_load_complete); | ||
2155 | if (ctx->blob) | 2155 | if (ctx->blob) |
2156 | goto fw_ready; | 2156 | goto fw_ready; |
2157 | /* On some ARM systems, the async request will fail, but the next sync | 2157 | /* On some ARM systems, the async request will fail, but the next sync |
2158 | * request works. For this reason, we dall through here | 2158 | * request works. For this reason, we fall through here |
2159 | */ | 2159 | */ |
2160 | } | 2160 | } |
2161 | err = request_firmware(&ctx->blob, ctx->fwname, | 2161 | err = request_firmware(&ctx->blob, ctx->fwname, |