diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2014-01-12 16:11:38 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-02-06 14:08:14 -0500 |
commit | 1a712907b90a5aad689e8757616537a506ba07f9 (patch) | |
tree | f547cd3d6233da33bf8a98f8362f0ed9ee4dd149 | |
parent | eeb405fd975fd5b684248d2d9039d685d34fac52 (diff) |
b43: Fix unload oops if firmware is not available
commit 0673effd41dba323d6a280ef37b5ef29f3f5a653 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: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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 291a1199df96..0b7edd36cfa2 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -2068,6 +2068,7 @@ void b43_do_release_fw(struct b43_firmware_file *fw) | |||
2068 | 2068 | ||
2069 | static void b43_release_firmware(struct b43_wldev *dev) | 2069 | static void b43_release_firmware(struct b43_wldev *dev) |
2070 | { | 2070 | { |
2071 | complete(&dev->fw_load_complete); | ||
2071 | b43_do_release_fw(&dev->fw.ucode); | 2072 | b43_do_release_fw(&dev->fw.ucode); |
2072 | b43_do_release_fw(&dev->fw.pcm); | 2073 | b43_do_release_fw(&dev->fw.pcm); |
2073 | b43_do_release_fw(&dev->fw.initvals); | 2074 | b43_do_release_fw(&dev->fw.initvals); |
@@ -2093,7 +2094,7 @@ static void b43_fw_cb(const struct firmware *firmware, void *context) | |||
2093 | struct b43_request_fw_context *ctx = context; | 2094 | struct b43_request_fw_context *ctx = context; |
2094 | 2095 | ||
2095 | ctx->blob = firmware; | 2096 | ctx->blob = firmware; |
2096 | complete(&ctx->fw_load_complete); | 2097 | complete(&ctx->dev->fw_load_complete); |
2097 | } | 2098 | } |
2098 | 2099 | ||
2099 | int b43_do_request_fw(struct b43_request_fw_context *ctx, | 2100 | 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 | } | 2141 | } |
2141 | if (async) { | 2142 | if (async) { |
2142 | /* do this part asynchronously */ | 2143 | /* do this part asynchronously */ |
2143 | init_completion(&ctx->fw_load_complete); | 2144 | init_completion(&ctx->dev->fw_load_complete); |
2144 | err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, | 2145 | err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, |
2145 | ctx->dev->dev->dev, GFP_KERNEL, | 2146 | ctx->dev->dev->dev, GFP_KERNEL, |
2146 | ctx, b43_fw_cb); | 2147 | ctx, b43_fw_cb); |
@@ -2148,12 +2149,11 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, | |||
2148 | pr_err("Unable to load firmware\n"); | 2149 | pr_err("Unable to load firmware\n"); |
2149 | return err; | 2150 | return err; |
2150 | } | 2151 | } |
2151 | /* stall here until fw ready */ | 2152 | wait_for_completion(&ctx->dev->fw_load_complete); |
2152 | wait_for_completion(&ctx->fw_load_complete); | ||
2153 | if (ctx->blob) | 2153 | if (ctx->blob) |
2154 | goto fw_ready; | 2154 | goto fw_ready; |
2155 | /* On some ARM systems, the async request will fail, but the next sync | 2155 | /* On some ARM systems, the async request will fail, but the next sync |
2156 | * request works. For this reason, we dall through here | 2156 | * request works. For this reason, we fall through here |
2157 | */ | 2157 | */ |
2158 | } | 2158 | } |
2159 | err = request_firmware(&ctx->blob, ctx->fwname, | 2159 | err = request_firmware(&ctx->blob, ctx->fwname, |