mirror of
				https://github.com/Ysurac/openmptcprouter.git
				synced 2025-03-09 15:40:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			574 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			574 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From d09ae51a4b676151edaf572bcd5f272b5532639f Mon Sep 17 00:00:00 2001
 | |
| From: Arend Van Spriel <arend.vanspriel@broadcom.com>
 | |
| Date: Thu, 22 Mar 2018 21:28:26 +0100
 | |
| Subject: [PATCH] brcmfmac: pass struct in brcmf_fw_get_firmwares()
 | |
| 
 | |
| Make the function brcmf_fw_get_firmwares() a bit more easy to extend
 | |
| using a structure to pass the request parameters.
 | |
| 
 | |
| Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
 | |
| Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
 | |
| Reviewed-by: Franky Lin <franky.lin@broadcom.com>
 | |
| Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
 | |
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 | |
| ---
 | |
|  .../broadcom/brcm80211/brcmfmac/firmware.c         | 175 ++++++++++++++-------
 | |
|  .../broadcom/brcm80211/brcmfmac/firmware.h         |  43 +++--
 | |
|  .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    |  38 ++++-
 | |
|  .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |  32 +++-
 | |
|  .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c |  43 ++++-
 | |
|  5 files changed, 245 insertions(+), 86 deletions(-)
 | |
| 
 | |
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
 | |
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
 | |
| @@ -438,18 +438,31 @@ void brcmf_fw_nvram_free(void *nvram)
 | |
|  
 | |
|  struct brcmf_fw {
 | |
|  	struct device *dev;
 | |
| -	u16 flags;
 | |
| -	const struct firmware *code;
 | |
| -	const char *nvram_name;
 | |
| -	u16 domain_nr;
 | |
| -	u16 bus_nr;
 | |
| -	void (*done)(struct device *dev, int err, const struct firmware *fw,
 | |
| -		     void *nvram_image, u32 nvram_len);
 | |
| +	struct brcmf_fw_request *req;
 | |
| +	u32 curpos;
 | |
| +	void (*done)(struct device *dev, int err, struct brcmf_fw_request *req);
 | |
|  };
 | |
|  
 | |
| +static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
 | |
| +
 | |
| +static void brcmf_fw_free_request(struct brcmf_fw_request *req)
 | |
| +{
 | |
| +	struct brcmf_fw_item *item;
 | |
| +	int i;
 | |
| +
 | |
| +	for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) {
 | |
| +		if (item->type == BRCMF_FW_TYPE_BINARY)
 | |
| +			release_firmware(item->binary);
 | |
| +		else if (item->type == BRCMF_FW_TYPE_NVRAM)
 | |
| +			brcmf_fw_nvram_free(item->nv_data.data);
 | |
| +	}
 | |
| +	kfree(req);
 | |
| +}
 | |
| +
 | |
|  static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
 | |
|  {
 | |
|  	struct brcmf_fw *fwctx = ctx;
 | |
| +	struct brcmf_fw_item *cur;
 | |
|  	u32 nvram_length = 0;
 | |
|  	void *nvram = NULL;
 | |
|  	u8 *data = NULL;
 | |
| @@ -457,83 +470,150 @@ static void brcmf_fw_request_nvram_done(
 | |
|  	bool raw_nvram;
 | |
|  
 | |
|  	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
 | |
| +
 | |
| +	cur = &fwctx->req->items[fwctx->curpos];
 | |
| +
 | |
|  	if (fw && fw->data) {
 | |
|  		data = (u8 *)fw->data;
 | |
|  		data_len = fw->size;
 | |
|  		raw_nvram = false;
 | |
|  	} else {
 | |
|  		data = bcm47xx_nvram_get_contents(&data_len);
 | |
| -		if (!data && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
 | |
| +		if (!data && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
 | |
|  			goto fail;
 | |
|  		raw_nvram = true;
 | |
|  	}
 | |
|  
 | |
|  	if (data)
 | |
|  		nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length,
 | |
| -					     fwctx->domain_nr, fwctx->bus_nr);
 | |
| +					     fwctx->req->domain_nr,
 | |
| +					     fwctx->req->bus_nr);
 | |
|  
 | |
|  	if (raw_nvram)
 | |
|  		bcm47xx_nvram_release_contents(data);
 | |
|  	release_firmware(fw);
 | |
| -	if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
 | |
| +	if (!nvram && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
 | |
|  		goto fail;
 | |
|  
 | |
| -	fwctx->done(fwctx->dev, 0, fwctx->code, nvram, nvram_length);
 | |
| -	kfree(fwctx);
 | |
| +	brcmf_dbg(TRACE, "nvram %p len %d\n", nvram, nvram_length);
 | |
| +	cur->nv_data.data = nvram;
 | |
| +	cur->nv_data.len = nvram_length;
 | |
|  	return;
 | |
|  
 | |
|  fail:
 | |
|  	brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
 | |
| -	release_firmware(fwctx->code);
 | |
| -	fwctx->done(fwctx->dev, -ENOENT, NULL, NULL, 0);
 | |
| +	fwctx->done(fwctx->dev, -ENOENT, NULL);
 | |
| +	brcmf_fw_free_request(fwctx->req);
 | |
|  	kfree(fwctx);
 | |
|  }
 | |
|  
 | |
| -static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx)
 | |
| +static int brcmf_fw_request_next_item(struct brcmf_fw *fwctx, bool async)
 | |
| +{
 | |
| +	struct brcmf_fw_item *cur;
 | |
| +	const struct firmware *fw = NULL;
 | |
| +	int ret;
 | |
| +
 | |
| +	cur = &fwctx->req->items[fwctx->curpos];
 | |
| +
 | |
| +	brcmf_dbg(TRACE, "%srequest for %s\n", async ? "async " : "",
 | |
| +		  cur->path);
 | |
| +
 | |
| +	if (async)
 | |
| +		ret = request_firmware_nowait(THIS_MODULE, true, cur->path,
 | |
| +					      fwctx->dev, GFP_KERNEL, fwctx,
 | |
| +					      brcmf_fw_request_done);
 | |
| +	else
 | |
| +		ret = request_firmware(&fw, cur->path, fwctx->dev);
 | |
| +
 | |
| +	if (ret < 0) {
 | |
| +		brcmf_fw_request_done(NULL, fwctx);
 | |
| +	} else if (!async && fw) {
 | |
| +		brcmf_dbg(TRACE, "firmware %s %sfound\n", cur->path,
 | |
| +			  fw ? "" : "not ");
 | |
| +		if (cur->type == BRCMF_FW_TYPE_BINARY)
 | |
| +			cur->binary = fw;
 | |
| +		else if (cur->type == BRCMF_FW_TYPE_NVRAM)
 | |
| +			brcmf_fw_request_nvram_done(fw, fwctx);
 | |
| +		else
 | |
| +			release_firmware(fw);
 | |
| +
 | |
| +		return -EAGAIN;
 | |
| +	}
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static void brcmf_fw_request_done(const struct firmware *fw, void *ctx)
 | |
|  {
 | |
|  	struct brcmf_fw *fwctx = ctx;
 | |
| +	struct brcmf_fw_item *cur;
 | |
|  	int ret = 0;
 | |
|  
 | |
| -	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
 | |
| -	if (!fw) {
 | |
| +	cur = &fwctx->req->items[fwctx->curpos];
 | |
| +
 | |
| +	brcmf_dbg(TRACE, "enter: firmware %s %sfound\n", cur->path,
 | |
| +		  fw ? "" : "not ");
 | |
| +
 | |
| +	if (fw) {
 | |
| +		if (cur->type == BRCMF_FW_TYPE_BINARY)
 | |
| +			cur->binary = fw;
 | |
| +		else if (cur->type == BRCMF_FW_TYPE_NVRAM)
 | |
| +			brcmf_fw_request_nvram_done(fw, fwctx);
 | |
| +		else
 | |
| +			release_firmware(fw);
 | |
| +	} else if (cur->type == BRCMF_FW_TYPE_NVRAM) {
 | |
| +		brcmf_fw_request_nvram_done(NULL, fwctx);
 | |
| +	} else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL)) {
 | |
|  		ret = -ENOENT;
 | |
|  		goto fail;
 | |
|  	}
 | |
| -	/* only requested code so done here */
 | |
| -	if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM))
 | |
| -		goto done;
 | |
| -
 | |
| -	fwctx->code = fw;
 | |
| -	ret = request_firmware_nowait(THIS_MODULE, true, fwctx->nvram_name,
 | |
| -				      fwctx->dev, GFP_KERNEL, fwctx,
 | |
| -				      brcmf_fw_request_nvram_done);
 | |
|  
 | |
| -	/* pass NULL to nvram callback for bcm47xx fallback */
 | |
| -	if (ret)
 | |
| -		brcmf_fw_request_nvram_done(NULL, fwctx);
 | |
| +	do {
 | |
| +		if (++fwctx->curpos == fwctx->req->n_items) {
 | |
| +			ret = 0;
 | |
| +			goto done;
 | |
| +		}
 | |
| +
 | |
| +		ret = brcmf_fw_request_next_item(fwctx, false);
 | |
| +	} while (ret == -EAGAIN);
 | |
| +
 | |
|  	return;
 | |
|  
 | |
|  fail:
 | |
| -	brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
 | |
| +	brcmf_dbg(TRACE, "failed err=%d: dev=%s, fw=%s\n", ret,
 | |
| +		  dev_name(fwctx->dev), cur->path);
 | |
| +	brcmf_fw_free_request(fwctx->req);
 | |
| +	fwctx->req = NULL;
 | |
|  done:
 | |
| -	fwctx->done(fwctx->dev, ret, fw, NULL, 0);
 | |
| +	fwctx->done(fwctx->dev, ret, fwctx->req);
 | |
|  	kfree(fwctx);
 | |
|  }
 | |
|  
 | |
| -int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
 | |
| -				const char *code, const char *nvram,
 | |
| -				void (*fw_cb)(struct device *dev, int err,
 | |
| -					      const struct firmware *fw,
 | |
| -					      void *nvram_image, u32 nvram_len),
 | |
| -				u16 domain_nr, u16 bus_nr)
 | |
| +static bool brcmf_fw_request_is_valid(struct brcmf_fw_request *req)
 | |
| +{
 | |
| +	struct brcmf_fw_item *item;
 | |
| +	int i;
 | |
| +
 | |
| +	if (!req->n_items)
 | |
| +		return false;
 | |
| +
 | |
| +	for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) {
 | |
| +		if (!item->path)
 | |
| +			return false;
 | |
| +	}
 | |
| +	return true;
 | |
| +}
 | |
| +
 | |
| +int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
 | |
| +			   void (*fw_cb)(struct device *dev, int err,
 | |
| +					 struct brcmf_fw_request *req))
 | |
|  {
 | |
|  	struct brcmf_fw *fwctx;
 | |
|  
 | |
|  	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
 | |
| -	if (!fw_cb || !code)
 | |
| +	if (!fw_cb)
 | |
|  		return -EINVAL;
 | |
|  
 | |
| -	if ((flags & BRCMF_FW_REQUEST_NVRAM) && !nvram)
 | |
| +	if (!brcmf_fw_request_is_valid(req))
 | |
|  		return -EINVAL;
 | |
|  
 | |
|  	fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL);
 | |
| @@ -541,26 +621,11 @@ int brcmf_fw_get_firmwares_pcie(struct d
 | |
|  		return -ENOMEM;
 | |
|  
 | |
|  	fwctx->dev = dev;
 | |
| -	fwctx->flags = flags;
 | |
| +	fwctx->req = req;
 | |
|  	fwctx->done = fw_cb;
 | |
| -	if (flags & BRCMF_FW_REQUEST_NVRAM)
 | |
| -		fwctx->nvram_name = nvram;
 | |
| -	fwctx->domain_nr = domain_nr;
 | |
| -	fwctx->bus_nr = bus_nr;
 | |
| -
 | |
| -	return request_firmware_nowait(THIS_MODULE, true, code, dev,
 | |
| -				       GFP_KERNEL, fwctx,
 | |
| -				       brcmf_fw_request_code_done);
 | |
| -}
 | |
|  
 | |
| -int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
 | |
| -			   const char *code, const char *nvram,
 | |
| -			   void (*fw_cb)(struct device *dev, int err,
 | |
| -					 const struct firmware *fw,
 | |
| -					 void *nvram_image, u32 nvram_len))
 | |
| -{
 | |
| -	return brcmf_fw_get_firmwares_pcie(dev, flags, code, nvram, fw_cb, 0,
 | |
| -					   0);
 | |
| +	brcmf_fw_request_next_item(fwctx, true);
 | |
| +	return 0;
 | |
|  }
 | |
|  
 | |
|  static void brcmf_fw_get_full_name(char fw_name[BRCMF_FW_NAME_LEN],
 | |
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
 | |
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
 | |
| @@ -16,10 +16,7 @@
 | |
|  #ifndef BRCMFMAC_FIRMWARE_H
 | |
|  #define BRCMFMAC_FIRMWARE_H
 | |
|  
 | |
| -#define BRCMF_FW_REQUEST		0x000F
 | |
| -#define  BRCMF_FW_REQUEST_NVRAM		0x0001
 | |
| -#define BRCMF_FW_REQ_FLAGS		0x00F0
 | |
| -#define  BRCMF_FW_REQ_NV_OPTIONAL	0x0010
 | |
| +#define BRCMF_FW_REQF_OPTIONAL		0x0001
 | |
|  
 | |
|  #define	BRCMF_FW_NAME_LEN		320
 | |
|  
 | |
| @@ -54,21 +51,39 @@ int brcmf_fw_map_chip_to_name(u32 chip,
 | |
|  			      u32 table_size, char fw_name[BRCMF_FW_NAME_LEN],
 | |
|  			      char nvram_name[BRCMF_FW_NAME_LEN]);
 | |
|  void brcmf_fw_nvram_free(void *nvram);
 | |
| +
 | |
| +enum brcmf_fw_type {
 | |
| +	BRCMF_FW_TYPE_BINARY,
 | |
| +	BRCMF_FW_TYPE_NVRAM
 | |
| +};
 | |
| +
 | |
| +struct brcmf_fw_item {
 | |
| +	const char *path;
 | |
| +	enum brcmf_fw_type type;
 | |
| +	u16 flags;
 | |
| +	union {
 | |
| +		const struct firmware *binary;
 | |
| +		struct {
 | |
| +			void *data;
 | |
| +			u32 len;
 | |
| +		} nv_data;
 | |
| +	};
 | |
| +};
 | |
| +
 | |
| +struct brcmf_fw_request {
 | |
| +	u16 domain_nr;
 | |
| +	u16 bus_nr;
 | |
| +	u32 n_items;
 | |
| +	struct brcmf_fw_item items[0];
 | |
| +};
 | |
| +
 | |
|  /*
 | |
|   * Request firmware(s) asynchronously. When the asynchronous request
 | |
|   * fails it will not use the callback, but call device_release_driver()
 | |
|   * instead which will call the driver .remove() callback.
 | |
|   */
 | |
| -int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
 | |
| -				const char *code, const char *nvram,
 | |
| -				void (*fw_cb)(struct device *dev, int err,
 | |
| -					      const struct firmware *fw,
 | |
| -					      void *nvram_image, u32 nvram_len),
 | |
| -				u16 domain_nr, u16 bus_nr);
 | |
| -int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
 | |
| -			   const char *code, const char *nvram,
 | |
| +int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
 | |
|  			   void (*fw_cb)(struct device *dev, int err,
 | |
| -					 const struct firmware *fw,
 | |
| -					 void *nvram_image, u32 nvram_len));
 | |
| +					 struct brcmf_fw_request *req));
 | |
|  
 | |
|  #endif /* BRCMFMAC_FIRMWARE_H */
 | |
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
 | |
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
 | |
| @@ -1651,15 +1651,19 @@ static const struct brcmf_buscore_ops br
 | |
|  	.write32 = brcmf_pcie_buscore_write32,
 | |
|  };
 | |
|  
 | |
| +#define BRCMF_PCIE_FW_CODE	0
 | |
| +#define BRCMF_PCIE_FW_NVRAM	1
 | |
| +
 | |
|  static void brcmf_pcie_setup(struct device *dev, int ret,
 | |
| -			     const struct firmware *fw,
 | |
| -			     void *nvram, u32 nvram_len)
 | |
| +			     struct brcmf_fw_request *fwreq)
 | |
|  {
 | |
| +	const struct firmware *fw;
 | |
| +	void *nvram;
 | |
|  	struct brcmf_bus *bus;
 | |
|  	struct brcmf_pciedev *pcie_bus_dev;
 | |
|  	struct brcmf_pciedev_info *devinfo;
 | |
|  	struct brcmf_commonring **flowrings;
 | |
| -	u32 i;
 | |
| +	u32 i, nvram_len;
 | |
|  
 | |
|  	/* check firmware loading result */
 | |
|  	if (ret)
 | |
| @@ -1670,6 +1674,11 @@ static void brcmf_pcie_setup(struct devi
 | |
|  	devinfo = pcie_bus_dev->devinfo;
 | |
|  	brcmf_pcie_attach(devinfo);
 | |
|  
 | |
| +	fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary;
 | |
| +	nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
 | |
| +	nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
 | |
| +	kfree(fwreq);
 | |
| +
 | |
|  	/* Some of the firmwares have the size of the memory of the device
 | |
|  	 * defined inside the firmware. This is because part of the memory in
 | |
|  	 * the device is shared and the devision is determined by FW. Parse
 | |
| @@ -1730,6 +1739,7 @@ static int
 | |
|  brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 | |
|  {
 | |
|  	int ret;
 | |
| +	struct brcmf_fw_request *fwreq;
 | |
|  	struct brcmf_pciedev_info *devinfo;
 | |
|  	struct brcmf_pciedev *pcie_bus_dev;
 | |
|  	struct brcmf_bus *bus;
 | |
| @@ -1800,12 +1810,26 @@ brcmf_pcie_probe(struct pci_dev *pdev, c
 | |
|  	if (ret)
 | |
|  		goto fail_bus;
 | |
|  
 | |
| -	ret = brcmf_fw_get_firmwares_pcie(bus->dev, BRCMF_FW_REQUEST_NVRAM |
 | |
| -						    BRCMF_FW_REQ_NV_OPTIONAL,
 | |
| -					  devinfo->fw_name, devinfo->nvram_name,
 | |
| -					  brcmf_pcie_setup, domain_nr, bus_nr);
 | |
| +	fwreq = kzalloc(sizeof(*fwreq) + 2 * sizeof(struct brcmf_fw_item),
 | |
| +			GFP_KERNEL);
 | |
| +	if (!fwreq) {
 | |
| +		ret = -ENOMEM;
 | |
| +		goto fail_bus;
 | |
| +	}
 | |
| +
 | |
| +	fwreq->items[BRCMF_PCIE_FW_CODE].path = devinfo->fw_name;
 | |
| +	fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
 | |
| +	fwreq->items[BRCMF_PCIE_FW_NVRAM].path = devinfo->nvram_name;
 | |
| +	fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
 | |
| +	fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
 | |
| +	fwreq->n_items = 2;
 | |
| +	fwreq->domain_nr = domain_nr;
 | |
| +	fwreq->bus_nr = bus_nr;
 | |
| +	ret = brcmf_fw_get_firmwares(bus->dev, fwreq, brcmf_pcie_setup);
 | |
|  	if (ret == 0)
 | |
|  		return 0;
 | |
| +
 | |
| +	kfree(fwreq);
 | |
|  fail_bus:
 | |
|  	kfree(bus->msgbuf);
 | |
|  	kfree(bus);
 | |
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
 | |
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
 | |
| @@ -4031,14 +4031,19 @@ static const struct brcmf_bus_ops brcmf_
 | |
|  	.get_fwname = brcmf_sdio_get_fwname,
 | |
|  };
 | |
|  
 | |
| +#define BRCMF_SDIO_FW_CODE	0
 | |
| +#define BRCMF_SDIO_FW_NVRAM	1
 | |
| +
 | |
|  static void brcmf_sdio_firmware_callback(struct device *dev, int err,
 | |
| -					 const struct firmware *code,
 | |
| -					 void *nvram, u32 nvram_len)
 | |
| +					 struct brcmf_fw_request *fwreq)
 | |
|  {
 | |
|  	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 | |
|  	struct brcmf_sdio_dev *sdiod = bus_if->bus_priv.sdio;
 | |
|  	struct brcmf_sdio *bus = sdiod->bus;
 | |
|  	struct brcmf_core *core = bus->sdio_core;
 | |
| +	const struct firmware *code;
 | |
| +	void *nvram;
 | |
| +	u32 nvram_len;
 | |
|  	u8 saveclk;
 | |
|  
 | |
|  	brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
 | |
| @@ -4046,6 +4051,11 @@ static void brcmf_sdio_firmware_callback
 | |
|  	if (err)
 | |
|  		goto fail;
 | |
|  
 | |
| +	code = fwreq->items[BRCMF_SDIO_FW_CODE].binary;
 | |
| +	nvram = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.data;
 | |
| +	nvram_len = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.len;
 | |
| +	kfree(fwreq);
 | |
| +
 | |
|  	/* try to download image and nvram to the dongle */
 | |
|  	bus->alp_only = true;
 | |
|  	err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
 | |
| @@ -4150,6 +4160,7 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
 | |
|  	int ret;
 | |
|  	struct brcmf_sdio *bus;
 | |
|  	struct workqueue_struct *wq;
 | |
| +	struct brcmf_fw_request *fwreq;
 | |
|  
 | |
|  	brcmf_dbg(TRACE, "Enter\n");
 | |
|  
 | |
| @@ -4240,11 +4251,24 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
 | |
|  	if (ret)
 | |
|  		goto fail;
 | |
|  
 | |
| -	ret = brcmf_fw_get_firmwares(sdiodev->dev, BRCMF_FW_REQUEST_NVRAM,
 | |
| -				     sdiodev->fw_name, sdiodev->nvram_name,
 | |
| +	fwreq = kzalloc(sizeof(fwreq) + 2 * sizeof(struct brcmf_fw_item),
 | |
| +			GFP_KERNEL);
 | |
| +	if (!fwreq) {
 | |
| +		ret = -ENOMEM;
 | |
| +		goto fail;
 | |
| +	}
 | |
| +
 | |
| +	fwreq->items[BRCMF_SDIO_FW_CODE].path = sdiodev->fw_name;
 | |
| +	fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
 | |
| +	fwreq->items[BRCMF_SDIO_FW_NVRAM].path = sdiodev->nvram_name;
 | |
| +	fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
 | |
| +	fwreq->n_items = 2;
 | |
| +
 | |
| +	ret = brcmf_fw_get_firmwares(sdiodev->dev, fwreq,
 | |
|  				     brcmf_sdio_firmware_callback);
 | |
|  	if (ret != 0) {
 | |
|  		brcmf_err("async firmware request failed: %d\n", ret);
 | |
| +		kfree(fwreq);
 | |
|  		goto fail;
 | |
|  	}
 | |
|  
 | |
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
 | |
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
 | |
| @@ -1155,18 +1155,23 @@ static const struct brcmf_bus_ops brcmf_
 | |
|  	.get_fwname = brcmf_usb_get_fwname,
 | |
|  };
 | |
|  
 | |
| +#define BRCMF_USB_FW_CODE	0
 | |
| +
 | |
|  static void brcmf_usb_probe_phase2(struct device *dev, int ret,
 | |
| -				   const struct firmware *fw,
 | |
| -				   void *nvram, u32 nvlen)
 | |
| +				   struct brcmf_fw_request *fwreq)
 | |
|  {
 | |
|  	struct brcmf_bus *bus = dev_get_drvdata(dev);
 | |
|  	struct brcmf_usbdev_info *devinfo = bus->bus_priv.usb->devinfo;
 | |
| +	const struct firmware *fw;
 | |
|  
 | |
|  	if (ret)
 | |
|  		goto error;
 | |
|  
 | |
|  	brcmf_dbg(USB, "Start fw downloading\n");
 | |
|  
 | |
| +	fw = fwreq->items[BRCMF_USB_FW_CODE].binary;
 | |
| +	kfree(fwreq);
 | |
| +
 | |
|  	ret = check_file(fw->data);
 | |
|  	if (ret < 0) {
 | |
|  		brcmf_err("invalid firmware\n");
 | |
| @@ -1200,6 +1205,7 @@ static int brcmf_usb_probe_cb(struct brc
 | |
|  	struct brcmf_bus *bus = NULL;
 | |
|  	struct brcmf_usbdev *bus_pub = NULL;
 | |
|  	struct device *dev = devinfo->dev;
 | |
| +	struct brcmf_fw_request *fwreq;
 | |
|  	int ret;
 | |
|  
 | |
|  	brcmf_dbg(USB, "Enter\n");
 | |
| @@ -1250,11 +1256,22 @@ static int brcmf_usb_probe_cb(struct brc
 | |
|  	if (ret)
 | |
|  		goto fail;
 | |
|  
 | |
| +	fwreq = kzalloc(sizeof(*fwreq) + sizeof(struct brcmf_fw_item),
 | |
| +			GFP_KERNEL);
 | |
| +	if (!fwreq) {
 | |
| +		ret = -ENOMEM;
 | |
| +		goto fail;
 | |
| +	}
 | |
| +
 | |
| +	fwreq->items[BRCMF_USB_FW_CODE].path = devinfo->fw_name;
 | |
| +	fwreq->items[BRCMF_USB_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
 | |
| +	fwreq->n_items = 1;
 | |
| +
 | |
|  	/* request firmware here */
 | |
| -	ret = brcmf_fw_get_firmwares(dev, 0, devinfo->fw_name, NULL,
 | |
| -				     brcmf_usb_probe_phase2);
 | |
| +	ret = brcmf_fw_get_firmwares(dev, fwreq, brcmf_usb_probe_phase2);
 | |
|  	if (ret) {
 | |
|  		brcmf_err("firmware request failed: %d\n", ret);
 | |
| +		kfree(fwreq);
 | |
|  		goto fail;
 | |
|  	}
 | |
|  
 | |
| @@ -1447,11 +1464,25 @@ static int brcmf_usb_reset_resume(struct
 | |
|  {
 | |
|  	struct usb_device *usb = interface_to_usbdev(intf);
 | |
|  	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
 | |
| +	struct brcmf_fw_request *fwreq;
 | |
| +	int ret;
 | |
|  
 | |
|  	brcmf_dbg(USB, "Enter\n");
 | |
|  
 | |
| -	return brcmf_fw_get_firmwares(&usb->dev, 0, devinfo->fw_name, NULL,
 | |
| -				      brcmf_usb_probe_phase2);
 | |
| +	fwreq = kzalloc(sizeof(*fwreq) + sizeof(struct brcmf_fw_item),
 | |
| +			GFP_KERNEL);
 | |
| +	if (!fwreq)
 | |
| +		return -ENOMEM;
 | |
| +
 | |
| +	fwreq->items[BRCMF_USB_FW_CODE].path = devinfo->fw_name;
 | |
| +	fwreq->items[BRCMF_USB_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
 | |
| +	fwreq->n_items = 1;
 | |
| +
 | |
| +	ret = brcmf_fw_get_firmwares(&usb->dev, fwreq, brcmf_usb_probe_phase2);
 | |
| +	if (ret < 0)
 | |
| +		kfree(fwreq);
 | |
| +
 | |
| +	return ret;
 | |
|  }
 | |
|  
 | |
|  #define BRCMF_USB_DEVICE(dev_id)	\
 |