diff options
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
| -rw-r--r-- | drivers/net/wireless/b43/main.c | 57 | 
1 files changed, 43 insertions, 14 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 16ab280359b..05682736e46 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2088,11 +2088,18 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error)  		b43warn(wl, text);  } +static void b43_fw_cb(const struct firmware *firmware, void *context) +{ +	struct b43_request_fw_context *ctx = context; + +	ctx->blob = firmware; +	complete(&ctx->fw_load_complete); +} +  int b43_do_request_fw(struct b43_request_fw_context *ctx,  		      const char *name, -		      struct b43_firmware_file *fw) +		      struct b43_firmware_file *fw, bool async)  { -	const struct firmware *blob;  	struct b43_fw_header *hdr;  	u32 size;  	int err; @@ -2131,11 +2138,31 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,  		B43_WARN_ON(1);  		return -ENOSYS;  	} -	err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev); +	if (async) { +		/* do this part asynchronously */ +		init_completion(&ctx->fw_load_complete); +		err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, +					      ctx->dev->dev->dev, GFP_KERNEL, +					      ctx, b43_fw_cb); +		if (err < 0) { +			pr_err("Unable to load firmware\n"); +			return err; +		} +		/* stall here until fw ready */ +		wait_for_completion(&ctx->fw_load_complete); +		if (ctx->blob) +			goto fw_ready; +	/* On some ARM systems, the async request will fail, but the next sync +	 * request works. For this reason, we dall through here +	 */ +	} +	err = request_firmware(&ctx->blob, ctx->fwname, +			       ctx->dev->dev->dev);  	if (err == -ENOENT) {  		snprintf(ctx->errors[ctx->req_type],  			 sizeof(ctx->errors[ctx->req_type]), -			 "Firmware file \"%s\" not found\n", ctx->fwname); +			 "Firmware file \"%s\" not found\n", +			 ctx->fwname);  		return err;  	} else if (err) {  		snprintf(ctx->errors[ctx->req_type], @@ -2144,14 +2171,15 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,  			 ctx->fwname, err);  		return err;  	} -	if (blob->size < sizeof(struct b43_fw_header)) +fw_ready: +	if (ctx->blob->size < sizeof(struct b43_fw_header))  		goto err_format; -	hdr = (struct b43_fw_header *)(blob->data); +	hdr = (struct b43_fw_header *)(ctx->blob->data);  	switch (hdr->type) {  	case B43_FW_TYPE_UCODE:  	case B43_FW_TYPE_PCM:  		size = be32_to_cpu(hdr->size); -		if (size != blob->size - sizeof(struct b43_fw_header)) +		if (size != ctx->blob->size - sizeof(struct b43_fw_header))  			goto err_format;  		/* fallthrough */  	case B43_FW_TYPE_IV: @@ -2162,7 +2190,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,  		goto err_format;  	} -	fw->data = blob; +	fw->data = ctx->blob;  	fw->filename = name;  	fw->type = ctx->req_type; @@ -2172,7 +2200,7 @@ err_format:  	snprintf(ctx->errors[ctx->req_type],  		 sizeof(ctx->errors[ctx->req_type]),  		 "Firmware file \"%s\" format error.\n", ctx->fwname); -	release_firmware(blob); +	release_firmware(ctx->blob);  	return -EPROTO;  } @@ -2223,7 +2251,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)  			goto err_no_ucode;  		}  	} -	err = b43_do_request_fw(ctx, filename, &fw->ucode); +	err = b43_do_request_fw(ctx, filename, &fw->ucode, true);  	if (err)  		goto err_load; @@ -2235,7 +2263,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)  	else  		goto err_no_pcm;  	fw->pcm_request_failed = false; -	err = b43_do_request_fw(ctx, filename, &fw->pcm); +	err = b43_do_request_fw(ctx, filename, &fw->pcm, false);  	if (err == -ENOENT) {  		/* We did not find a PCM file? Not fatal, but  		 * core rev <= 10 must do without hwcrypto then. */ @@ -2296,7 +2324,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)  	default:  		goto err_no_initvals;  	} -	err = b43_do_request_fw(ctx, filename, &fw->initvals); +	err = b43_do_request_fw(ctx, filename, &fw->initvals, false);  	if (err)  		goto err_load; @@ -2355,7 +2383,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)  	default:  		goto err_no_initvals;  	} -	err = b43_do_request_fw(ctx, filename, &fw->initvals_band); +	err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false);  	if (err)  		goto err_load; @@ -4186,7 +4214,6 @@ redo:  	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) { @@ -5406,6 +5433,7 @@ static void b43_bcma_remove(struct bcma_device *core)  	/* We must cancel any work here before unregistering from ieee80211,  	 * as the ieee80211 unreg will destroy the workqueue. */  	cancel_work_sync(&wldev->restart_work); +	cancel_work_sync(&wl->firmware_load);  	B43_WARN_ON(!wl);  	if (!wldev->fw.ucode.data) @@ -5482,6 +5510,7 @@ static void b43_ssb_remove(struct ssb_device *sdev)  	/* We must cancel any work here before unregistering from ieee80211,  	 * as the ieee80211 unreg will destroy the workqueue. */  	cancel_work_sync(&wldev->restart_work); +	cancel_work_sync(&wl->firmware_load);  	B43_WARN_ON(!wl);  	if (!wldev->fw.ucode.data)  |