mac80211: backport brcmfmac firmware & clm_blob loading rework
It backports remaining brcmfmac changes from 4.17. Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
This commit is contained in:
		| @@ -0,0 +1,574 @@ | |||||||
|  | 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)	\ | ||||||
| @@ -0,0 +1,328 @@ | |||||||
|  | From 2baa3aaee27f137b8db9a9224d0fe9b281d28e34 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Arend Van Spriel <arend.vanspriel@broadcom.com> | ||||||
|  | Date: Thu, 22 Mar 2018 21:28:27 +0100 | ||||||
|  | Subject: [PATCH] brcmfmac: introduce brcmf_fw_alloc_request() function | ||||||
|  |  | ||||||
|  | The function brcmf_fw_alloc_request() takes a list of required files | ||||||
|  | and allocated the struct brcmf_fw_request instance accordingly. The | ||||||
|  | request can be modified by the caller before being passed to the | ||||||
|  | brcmf_fw_request_firmwares() function. | ||||||
|  |  | ||||||
|  | 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         | 58 ++++++++++++++++++++++ | ||||||
|  |  .../broadcom/brcm80211/brcmfmac/firmware.h         | 11 ++++ | ||||||
|  |  .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    | 58 ++++++++++++---------- | ||||||
|  |  .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    | 38 ++++++++------ | ||||||
|  |  .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 42 +++++++++------- | ||||||
|  |  5 files changed, 147 insertions(+), 60 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||||
|  | @@ -688,3 +688,61 @@ int brcmf_fw_map_chip_to_name(u32 chip, | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +struct brcmf_fw_request * | ||||||
|  | +brcmf_fw_alloc_request(u32 chip, u32 chiprev, | ||||||
|  | +		       struct brcmf_firmware_mapping mapping_table[], | ||||||
|  | +		       u32 table_size, struct brcmf_fw_name *fwnames, | ||||||
|  | +		       u32 n_fwnames) | ||||||
|  | +{ | ||||||
|  | +	struct brcmf_fw_request *fwreq; | ||||||
|  | +	char chipname[12]; | ||||||
|  | +	const char *mp_path; | ||||||
|  | +	u32 i, j; | ||||||
|  | +	char end; | ||||||
|  | +	size_t reqsz; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < table_size; i++) { | ||||||
|  | +		if (mapping_table[i].chipid == chip && | ||||||
|  | +		    mapping_table[i].revmask & BIT(chiprev)) | ||||||
|  | +			break; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (i == table_size) { | ||||||
|  | +		brcmf_err("Unknown chipid %d [%d]\n", chip, chiprev); | ||||||
|  | +		return NULL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	reqsz = sizeof(*fwreq) + n_fwnames * sizeof(struct brcmf_fw_item); | ||||||
|  | +	fwreq = kzalloc(reqsz, GFP_KERNEL); | ||||||
|  | +	if (!fwreq) | ||||||
|  | +		return NULL; | ||||||
|  | + | ||||||
|  | +	brcmf_chip_name(chip, chiprev, chipname, sizeof(chipname)); | ||||||
|  | + | ||||||
|  | +	brcmf_info("using %s for chip %s\n", | ||||||
|  | +		   mapping_table[i].fw_base, chipname); | ||||||
|  | + | ||||||
|  | +	mp_path = brcmf_mp_global.firmware_path; | ||||||
|  | +	end = mp_path[strlen(mp_path) - 1]; | ||||||
|  | +	fwreq->n_items = n_fwnames; | ||||||
|  | + | ||||||
|  | +	for (j = 0; j < n_fwnames; j++) { | ||||||
|  | +		fwreq->items[j].path = fwnames[j].path; | ||||||
|  | +		/* check if firmware path is provided by module parameter */ | ||||||
|  | +		if (brcmf_mp_global.firmware_path[0] != '\0') { | ||||||
|  | +			strlcpy(fwnames[j].path, mp_path, | ||||||
|  | +				BRCMF_FW_NAME_LEN); | ||||||
|  | + | ||||||
|  | +			if (end != '/') { | ||||||
|  | +				strlcat(fwnames[j].path, "/", | ||||||
|  | +					BRCMF_FW_NAME_LEN); | ||||||
|  | +			} | ||||||
|  | +		} | ||||||
|  | +		brcmf_fw_get_full_name(fwnames[j].path, | ||||||
|  | +				       mapping_table[i].fw_base, | ||||||
|  | +				       fwnames[j].extension); | ||||||
|  | +		fwreq->items[j].path = fwnames[j].path; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return fwreq; | ||||||
|  | +} | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h | ||||||
|  | @@ -77,6 +77,17 @@ struct brcmf_fw_request { | ||||||
|  |  	struct brcmf_fw_item items[0]; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | +struct brcmf_fw_name { | ||||||
|  | +	const char *extension; | ||||||
|  | +	char *path; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct brcmf_fw_request * | ||||||
|  | +brcmf_fw_alloc_request(u32 chip, u32 chiprev, | ||||||
|  | +		       struct brcmf_firmware_mapping mapping_table[], | ||||||
|  | +		       u32 table_size, struct brcmf_fw_name *fwnames, | ||||||
|  | +		       u32 n_fwnames); | ||||||
|  | + | ||||||
|  |  /* | ||||||
|  |   * Request firmware(s) asynchronously. When the asynchronous request | ||||||
|  |   * fails it will not use the callback, but call device_release_driver() | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||||
|  | @@ -1735,6 +1735,31 @@ fail: | ||||||
|  |  	device_release_driver(dev); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static struct brcmf_fw_request * | ||||||
|  | +brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) | ||||||
|  | +{ | ||||||
|  | +	struct brcmf_fw_request *fwreq; | ||||||
|  | +	struct brcmf_fw_name fwnames[] = { | ||||||
|  | +		{ ".bin", devinfo->fw_name }, | ||||||
|  | +		{ ".txt", devinfo->nvram_name }, | ||||||
|  | +	}; | ||||||
|  | + | ||||||
|  | +	fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev, | ||||||
|  | +				       brcmf_pcie_fwnames, | ||||||
|  | +				       ARRAY_SIZE(brcmf_pcie_fwnames), | ||||||
|  | +				       fwnames, ARRAY_SIZE(fwnames)); | ||||||
|  | +	if (!fwreq) | ||||||
|  | +		return NULL; | ||||||
|  | + | ||||||
|  | +	fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY; | ||||||
|  | +	fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; | ||||||
|  | +	fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL; | ||||||
|  | +	fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus); | ||||||
|  | +	fwreq->bus_nr = devinfo->pdev->bus->number; | ||||||
|  | + | ||||||
|  | +	return fwreq; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static int | ||||||
|  |  brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||||||
|  |  { | ||||||
|  | @@ -1743,13 +1768,8 @@ brcmf_pcie_probe(struct pci_dev *pdev, c | ||||||
|  |  	struct brcmf_pciedev_info *devinfo; | ||||||
|  |  	struct brcmf_pciedev *pcie_bus_dev; | ||||||
|  |  	struct brcmf_bus *bus; | ||||||
|  | -	u16 domain_nr; | ||||||
|  | -	u16 bus_nr; | ||||||
|  |   | ||||||
|  | -	domain_nr = pci_domain_nr(pdev->bus) + 1; | ||||||
|  | -	bus_nr = pdev->bus->number; | ||||||
|  | -	brcmf_dbg(PCIE, "Enter %x:%x (%d/%d)\n", pdev->vendor, pdev->device, | ||||||
|  | -		  domain_nr, bus_nr); | ||||||
|  | +	brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device); | ||||||
|  |   | ||||||
|  |  	ret = -ENOMEM; | ||||||
|  |  	devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); | ||||||
|  | @@ -1803,33 +1823,19 @@ brcmf_pcie_probe(struct pci_dev *pdev, c | ||||||
|  |  	bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot); | ||||||
|  |  	dev_set_drvdata(&pdev->dev, bus); | ||||||
|  |   | ||||||
|  | -	ret = brcmf_fw_map_chip_to_name(devinfo->ci->chip, devinfo->ci->chiprev, | ||||||
|  | -					brcmf_pcie_fwnames, | ||||||
|  | -					ARRAY_SIZE(brcmf_pcie_fwnames), | ||||||
|  | -					devinfo->fw_name, devinfo->nvram_name); | ||||||
|  | -	if (ret) | ||||||
|  | -		goto fail_bus; | ||||||
|  | - | ||||||
|  | -	fwreq = kzalloc(sizeof(*fwreq) + 2 * sizeof(struct brcmf_fw_item), | ||||||
|  | -			GFP_KERNEL); | ||||||
|  | +	fwreq = brcmf_pcie_prepare_fw_request(devinfo); | ||||||
|  |  	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; | ||||||
|  | +	if (ret < 0) { | ||||||
|  | +		kfree(fwreq); | ||||||
|  | +		goto fail_bus; | ||||||
|  | +	} | ||||||
|  | +	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 | ||||||
|  | @@ -4155,6 +4155,28 @@ fail: | ||||||
|  |  	device_release_driver(dev); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static struct brcmf_fw_request * | ||||||
|  | +brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) | ||||||
|  | +{ | ||||||
|  | +	struct brcmf_fw_request *fwreq; | ||||||
|  | +	struct brcmf_fw_name fwnames[] = { | ||||||
|  | +		{ ".bin", bus->sdiodev->fw_name }, | ||||||
|  | +		{ ".txt", bus->sdiodev->nvram_name }, | ||||||
|  | +	}; | ||||||
|  | + | ||||||
|  | +	fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev, | ||||||
|  | +				       brcmf_sdio_fwnames, | ||||||
|  | +				       ARRAY_SIZE(brcmf_sdio_fwnames), | ||||||
|  | +				       fwnames, ARRAY_SIZE(fwnames)); | ||||||
|  | +	if (!fwreq) | ||||||
|  | +		return NULL; | ||||||
|  | + | ||||||
|  | +	fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY; | ||||||
|  | +	fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; | ||||||
|  | + | ||||||
|  | +	return fwreq; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) | ||||||
|  |  { | ||||||
|  |  	int ret; | ||||||
|  | @@ -4244,26 +4266,12 @@ struct brcmf_sdio *brcmf_sdio_probe(stru | ||||||
|  |   | ||||||
|  |  	brcmf_dbg(INFO, "completed!!\n"); | ||||||
|  |   | ||||||
|  | -	ret = brcmf_fw_map_chip_to_name(bus->ci->chip, bus->ci->chiprev, | ||||||
|  | -					brcmf_sdio_fwnames, | ||||||
|  | -					ARRAY_SIZE(brcmf_sdio_fwnames), | ||||||
|  | -					sdiodev->fw_name, sdiodev->nvram_name); | ||||||
|  | -	if (ret) | ||||||
|  | -		goto fail; | ||||||
|  | - | ||||||
|  | -	fwreq = kzalloc(sizeof(fwreq) + 2 * sizeof(struct brcmf_fw_item), | ||||||
|  | -			GFP_KERNEL); | ||||||
|  | +	fwreq = brcmf_sdio_prepare_fw_request(bus); | ||||||
|  |  	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) { | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | ||||||
|  | @@ -1200,6 +1200,27 @@ error: | ||||||
|  |  	device_release_driver(dev); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static struct brcmf_fw_request * | ||||||
|  | +brcmf_usb_prepare_fw_request(struct brcmf_usbdev_info *devinfo) | ||||||
|  | +{ | ||||||
|  | +	struct brcmf_fw_request *fwreq; | ||||||
|  | +	struct brcmf_fw_name fwnames[] = { | ||||||
|  | +		{ ".bin", devinfo->fw_name }, | ||||||
|  | +	}; | ||||||
|  | + | ||||||
|  | +	fwreq = brcmf_fw_alloc_request(devinfo->bus_pub.devid, | ||||||
|  | +				       devinfo->bus_pub.chiprev, | ||||||
|  | +				       brcmf_usb_fwnames, | ||||||
|  | +				       ARRAY_SIZE(brcmf_usb_fwnames), | ||||||
|  | +				       fwnames, ARRAY_SIZE(fwnames)); | ||||||
|  | +	if (!fwreq) | ||||||
|  | +		return NULL; | ||||||
|  | + | ||||||
|  | +	fwreq->items[BRCMF_USB_FW_CODE].type = BRCMF_FW_TYPE_BINARY; | ||||||
|  | + | ||||||
|  | +	return fwreq; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) | ||||||
|  |  { | ||||||
|  |  	struct brcmf_bus *bus = NULL; | ||||||
|  | @@ -1249,24 +1270,12 @@ static int brcmf_usb_probe_cb(struct brc | ||||||
|  |  	bus->chip = bus_pub->devid; | ||||||
|  |  	bus->chiprev = bus_pub->chiprev; | ||||||
|  |   | ||||||
|  | -	ret = brcmf_fw_map_chip_to_name(bus_pub->devid, bus_pub->chiprev, | ||||||
|  | -					brcmf_usb_fwnames, | ||||||
|  | -					ARRAY_SIZE(brcmf_usb_fwnames), | ||||||
|  | -					devinfo->fw_name, NULL); | ||||||
|  | -	if (ret) | ||||||
|  | -		goto fail; | ||||||
|  | - | ||||||
|  | -	fwreq = kzalloc(sizeof(*fwreq) + sizeof(struct brcmf_fw_item), | ||||||
|  | -			GFP_KERNEL); | ||||||
|  | +	fwreq = brcmf_usb_prepare_fw_request(devinfo); | ||||||
|  |  	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, fwreq, brcmf_usb_probe_phase2); | ||||||
|  |  	if (ret) { | ||||||
|  | @@ -1469,15 +1478,10 @@ static int brcmf_usb_reset_resume(struct | ||||||
|  |   | ||||||
|  |  	brcmf_dbg(USB, "Enter\n"); | ||||||
|  |   | ||||||
|  | -	fwreq = kzalloc(sizeof(*fwreq) + sizeof(struct brcmf_fw_item), | ||||||
|  | -			GFP_KERNEL); | ||||||
|  | +	fwreq = brcmf_usb_prepare_fw_request(devinfo); | ||||||
|  |  	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); | ||||||
| @@ -0,0 +1,231 @@ | |||||||
|  | From bf7a7b37f6ef5090a2bae7e7ae23cd26b741cca4 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Arend Van Spriel <arend.vanspriel@broadcom.com> | ||||||
|  | Date: Thu, 22 Mar 2018 21:28:28 +0100 | ||||||
|  | Subject: [PATCH] brcmfmac: add extension to .get_fwname() callbacks | ||||||
|  |  | ||||||
|  | This changes the bus layer api by having the caller provide an | ||||||
|  | extension. With this the callback can use brcmf_fw_alloc_request() | ||||||
|  | to get the needed firmware name. | ||||||
|  |  | ||||||
|  | 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> | ||||||
|  | --- | ||||||
|  |  .../net/wireless/broadcom/brcm80211/brcmfmac/bus.h |  6 +-- | ||||||
|  |  .../wireless/broadcom/brcm80211/brcmfmac/common.c  | 43 +++------------------- | ||||||
|  |  .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    | 27 +++++++------- | ||||||
|  |  .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    | 26 +++++++------ | ||||||
|  |  .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 27 ++++++++------ | ||||||
|  |  5 files changed, 51 insertions(+), 78 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | ||||||
|  | @@ -88,7 +88,7 @@ struct brcmf_bus_ops { | ||||||
|  |  	void (*wowl_config)(struct device *dev, bool enabled); | ||||||
|  |  	size_t (*get_ramsize)(struct device *dev); | ||||||
|  |  	int (*get_memdump)(struct device *dev, void *data, size_t len); | ||||||
|  | -	int (*get_fwname)(struct device *dev, uint chip, uint chiprev, | ||||||
|  | +	int (*get_fwname)(struct device *dev, const char *ext, | ||||||
|  |  			  unsigned char *fw_name); | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | @@ -228,10 +228,10 @@ int brcmf_bus_get_memdump(struct brcmf_b | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static inline | ||||||
|  | -int brcmf_bus_get_fwname(struct brcmf_bus *bus, uint chip, uint chiprev, | ||||||
|  | +int brcmf_bus_get_fwname(struct brcmf_bus *bus, const char *ext, | ||||||
|  |  			 unsigned char *fw_name) | ||||||
|  |  { | ||||||
|  | -	return bus->ops->get_fwname(bus->dev, chip, chiprev, fw_name); | ||||||
|  | +	return bus->ops->get_fwname(bus->dev, ext, fw_name); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  /* | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | ||||||
|  | @@ -129,42 +129,9 @@ static int brcmf_c_download(struct brcmf | ||||||
|  |  	return err; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -static int brcmf_c_get_clm_name(struct brcmf_if *ifp, u8 *clm_name) | ||||||
|  | -{ | ||||||
|  | -	struct brcmf_bus *bus = ifp->drvr->bus_if; | ||||||
|  | -	u8 fw_name[BRCMF_FW_NAME_LEN]; | ||||||
|  | -	u8 *ptr; | ||||||
|  | -	size_t len; | ||||||
|  | -	s32 err; | ||||||
|  | - | ||||||
|  | -	memset(fw_name, 0, BRCMF_FW_NAME_LEN); | ||||||
|  | -	err = brcmf_bus_get_fwname(bus, bus->chip, bus->chiprev, fw_name); | ||||||
|  | -	if (err) { | ||||||
|  | -		brcmf_err("get firmware name failed (%d)\n", err); | ||||||
|  | -		goto done; | ||||||
|  | -	} | ||||||
|  | - | ||||||
|  | -	/* generate CLM blob file name */ | ||||||
|  | -	ptr = strrchr(fw_name, '.'); | ||||||
|  | -	if (!ptr) { | ||||||
|  | -		err = -ENOENT; | ||||||
|  | -		goto done; | ||||||
|  | -	} | ||||||
|  | - | ||||||
|  | -	len = ptr - fw_name + 1; | ||||||
|  | -	if (len + strlen(".clm_blob") > BRCMF_FW_NAME_LEN) { | ||||||
|  | -		err = -E2BIG; | ||||||
|  | -	} else { | ||||||
|  | -		strlcpy(clm_name, fw_name, len); | ||||||
|  | -		strlcat(clm_name, ".clm_blob", BRCMF_FW_NAME_LEN); | ||||||
|  | -	} | ||||||
|  | -done: | ||||||
|  | -	return err; | ||||||
|  | -} | ||||||
|  | - | ||||||
|  |  static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) | ||||||
|  |  { | ||||||
|  | -	struct device *dev = ifp->drvr->bus_if->dev; | ||||||
|  | +	struct brcmf_bus *bus = ifp->drvr->bus_if; | ||||||
|  |  	struct brcmf_dload_data_le *chunk_buf; | ||||||
|  |  	const struct firmware *clm = NULL; | ||||||
|  |  	u8 clm_name[BRCMF_FW_NAME_LEN]; | ||||||
|  | @@ -177,16 +144,16 @@ static int brcmf_c_process_clm_blob(stru | ||||||
|  |   | ||||||
|  |  	brcmf_dbg(TRACE, "Enter\n"); | ||||||
|  |   | ||||||
|  | -	memset(clm_name, 0, BRCMF_FW_NAME_LEN); | ||||||
|  | -	err = brcmf_c_get_clm_name(ifp, clm_name); | ||||||
|  | +	memset(clm_name, 0, sizeof(clm_name)); | ||||||
|  | +	err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name); | ||||||
|  |  	if (err) { | ||||||
|  |  		brcmf_err("get CLM blob file name failed (%d)\n", err); | ||||||
|  |  		return err; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -	err = request_firmware(&clm, clm_name, dev); | ||||||
|  | +	err = request_firmware(&clm, clm_name, bus->dev); | ||||||
|  |  	if (err) { | ||||||
|  | -		brcmf_info("no clm_blob available(err=%d), device may have limited channels available\n", | ||||||
|  | +		brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n", | ||||||
|  |  			   err); | ||||||
|  |  		return 0; | ||||||
|  |  	} | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||||
|  | @@ -1350,23 +1350,24 @@ static int brcmf_pcie_get_memdump(struct | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -static int brcmf_pcie_get_fwname(struct device *dev, u32 chip, u32 chiprev, | ||||||
|  | -				 u8 *fw_name) | ||||||
|  | +static | ||||||
|  | +int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name) | ||||||
|  |  { | ||||||
|  |  	struct brcmf_bus *bus_if = dev_get_drvdata(dev); | ||||||
|  | -	struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie; | ||||||
|  | -	struct brcmf_pciedev_info *devinfo = buspub->devinfo; | ||||||
|  | -	int ret = 0; | ||||||
|  | +	struct brcmf_fw_request *fwreq; | ||||||
|  | +	struct brcmf_fw_name fwnames[] = { | ||||||
|  | +		{ ext, fw_name }, | ||||||
|  | +	}; | ||||||
|  |   | ||||||
|  | -	if (devinfo->fw_name[0] != '\0') | ||||||
|  | -		strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN); | ||||||
|  | -	else | ||||||
|  | -		ret = brcmf_fw_map_chip_to_name(chip, chiprev, | ||||||
|  | -						brcmf_pcie_fwnames, | ||||||
|  | -						ARRAY_SIZE(brcmf_pcie_fwnames), | ||||||
|  | -						fw_name, NULL); | ||||||
|  | +	fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, | ||||||
|  | +				       brcmf_pcie_fwnames, | ||||||
|  | +				       ARRAY_SIZE(brcmf_pcie_fwnames), | ||||||
|  | +				       fwnames, ARRAY_SIZE(fwnames)); | ||||||
|  | +	if (!fwreq) | ||||||
|  | +		return -ENOMEM; | ||||||
|  |   | ||||||
|  | -	return ret; | ||||||
|  | +	kfree(fwreq); | ||||||
|  | +	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | ||||||
|  | @@ -4000,22 +4000,24 @@ brcmf_sdio_watchdog(unsigned long data) | ||||||
|  |  	} | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -static int brcmf_sdio_get_fwname(struct device *dev, u32 chip, u32 chiprev, | ||||||
|  | -				 u8 *fw_name) | ||||||
|  | +static | ||||||
|  | +int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name) | ||||||
|  |  { | ||||||
|  |  	struct brcmf_bus *bus_if = dev_get_drvdata(dev); | ||||||
|  | -	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; | ||||||
|  | -	int ret = 0; | ||||||
|  | +	struct brcmf_fw_request *fwreq; | ||||||
|  | +	struct brcmf_fw_name fwnames[] = { | ||||||
|  | +		{ ext, fw_name }, | ||||||
|  | +	}; | ||||||
|  |   | ||||||
|  | -	if (sdiodev->fw_name[0] != '\0') | ||||||
|  | -		strlcpy(fw_name, sdiodev->fw_name, BRCMF_FW_NAME_LEN); | ||||||
|  | -	else | ||||||
|  | -		ret = brcmf_fw_map_chip_to_name(chip, chiprev, | ||||||
|  | -						brcmf_sdio_fwnames, | ||||||
|  | -						ARRAY_SIZE(brcmf_sdio_fwnames), | ||||||
|  | -						fw_name, NULL); | ||||||
|  | +	fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, | ||||||
|  | +				       brcmf_sdio_fwnames, | ||||||
|  | +				       ARRAY_SIZE(brcmf_sdio_fwnames), | ||||||
|  | +				       fwnames, ARRAY_SIZE(fwnames)); | ||||||
|  | +	if (!fwreq) | ||||||
|  | +		return -ENOMEM; | ||||||
|  |   | ||||||
|  | -	return ret; | ||||||
|  | +	kfree(fwreq); | ||||||
|  | +	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | ||||||
|  | @@ -1128,21 +1128,24 @@ static void brcmf_usb_wowl_config(struct | ||||||
|  |  		device_set_wakeup_enable(devinfo->dev, false); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev, | ||||||
|  | -				u8 *fw_name) | ||||||
|  | +static | ||||||
|  | +int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name) | ||||||
|  |  { | ||||||
|  | -	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); | ||||||
|  | -	int ret = 0; | ||||||
|  | +	struct brcmf_bus *bus = dev_get_drvdata(dev); | ||||||
|  | +	struct brcmf_fw_request *fwreq; | ||||||
|  | +	struct brcmf_fw_name fwnames[] = { | ||||||
|  | +		{ ext, fw_name }, | ||||||
|  | +	}; | ||||||
|  |   | ||||||
|  | -	if (devinfo->fw_name[0] != '\0') | ||||||
|  | -		strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN); | ||||||
|  | -	else | ||||||
|  | -		ret = brcmf_fw_map_chip_to_name(chip, chiprev, | ||||||
|  | -						brcmf_usb_fwnames, | ||||||
|  | -						ARRAY_SIZE(brcmf_usb_fwnames), | ||||||
|  | -						fw_name, NULL); | ||||||
|  | +	fwreq = brcmf_fw_alloc_request(bus->chip, bus->chiprev, | ||||||
|  | +				       brcmf_usb_fwnames, | ||||||
|  | +				       ARRAY_SIZE(brcmf_usb_fwnames), | ||||||
|  | +				       fwnames, ARRAY_SIZE(fwnames)); | ||||||
|  | +	if (!fwreq) | ||||||
|  | +		return -ENOMEM; | ||||||
|  |   | ||||||
|  | -	return ret; | ||||||
|  | +	kfree(fwreq); | ||||||
|  | +	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static const struct brcmf_bus_ops brcmf_usb_bus_ops = { | ||||||
| @@ -0,0 +1,92 @@ | |||||||
|  | From 18c2b20e276e04476a3350b4a92c1dfad725d45d Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Arend Van Spriel <arend.vanspriel@broadcom.com> | ||||||
|  | Date: Thu, 22 Mar 2018 21:28:29 +0100 | ||||||
|  | Subject: [PATCH] brcmfmac: get rid of brcmf_fw_map_chip_to_name() | ||||||
|  |  | ||||||
|  | The function is no longer used so removing it. | ||||||
|  |  | ||||||
|  | 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         | 53 ---------------------- | ||||||
|  |  .../broadcom/brcm80211/brcmfmac/firmware.h         |  4 -- | ||||||
|  |  2 files changed, 57 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||||
|  | @@ -635,59 +635,6 @@ static void brcmf_fw_get_full_name(char | ||||||
|  |  	strlcat(fw_name, extension, BRCMF_FW_NAME_LEN); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev, | ||||||
|  | -			      struct brcmf_firmware_mapping mapping_table[], | ||||||
|  | -			      u32 table_size, char fw_name[BRCMF_FW_NAME_LEN], | ||||||
|  | -			      char nvram_name[BRCMF_FW_NAME_LEN]) | ||||||
|  | -{ | ||||||
|  | -	char chipname[12]; | ||||||
|  | -	u32 i; | ||||||
|  | -	char end; | ||||||
|  | - | ||||||
|  | -	for (i = 0; i < table_size; i++) { | ||||||
|  | -		if (mapping_table[i].chipid == chip && | ||||||
|  | -		    mapping_table[i].revmask & BIT(chiprev)) | ||||||
|  | -			break; | ||||||
|  | -	} | ||||||
|  | - | ||||||
|  | -	if (i == table_size) { | ||||||
|  | -		brcmf_err("Unknown chipid %d [%d]\n", chip, chiprev); | ||||||
|  | -		return -ENODEV; | ||||||
|  | -	} | ||||||
|  | - | ||||||
|  | -	brcmf_chip_name(chip, chiprev, chipname, sizeof(chipname)); | ||||||
|  | - | ||||||
|  | -	/* check if firmware path is provided by module parameter */ | ||||||
|  | -	if (brcmf_mp_global.firmware_path[0] != '\0') { | ||||||
|  | -		if (fw_name) | ||||||
|  | -			strlcpy(fw_name, brcmf_mp_global.firmware_path, | ||||||
|  | -				BRCMF_FW_NAME_LEN); | ||||||
|  | -		if (nvram_name) | ||||||
|  | -			strlcpy(nvram_name, brcmf_mp_global.firmware_path, | ||||||
|  | -				BRCMF_FW_NAME_LEN); | ||||||
|  | - | ||||||
|  | -		end = brcmf_mp_global.firmware_path[ | ||||||
|  | -				strlen(brcmf_mp_global.firmware_path) - 1]; | ||||||
|  | -		if (end != '/') { | ||||||
|  | -			if (fw_name) | ||||||
|  | -				strlcat(fw_name, "/", BRCMF_FW_NAME_LEN); | ||||||
|  | -			if (nvram_name) | ||||||
|  | -				strlcat(nvram_name, "/", BRCMF_FW_NAME_LEN); | ||||||
|  | -		} | ||||||
|  | -	} | ||||||
|  | - | ||||||
|  | -	brcmf_info("using %s for chip %s\n", | ||||||
|  | -		   mapping_table[i].fw_base, chipname); | ||||||
|  | -	if (fw_name) | ||||||
|  | -		brcmf_fw_get_full_name(fw_name, | ||||||
|  | -				       mapping_table[i].fw_base, ".bin"); | ||||||
|  | -	if (nvram_name) | ||||||
|  | -		brcmf_fw_get_full_name(nvram_name, | ||||||
|  | -				       mapping_table[i].fw_base, ".txt"); | ||||||
|  | - | ||||||
|  | -	return 0; | ||||||
|  | -} | ||||||
|  | - | ||||||
|  |  struct brcmf_fw_request * | ||||||
|  |  brcmf_fw_alloc_request(u32 chip, u32 chiprev, | ||||||
|  |  		       struct brcmf_firmware_mapping mapping_table[], | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h | ||||||
|  | @@ -46,10 +46,6 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw | ||||||
|  |  #define BRCMF_FW_ENTRY(chipid, mask, name) \ | ||||||
|  |  	{ chipid, mask, BRCM_ ## name ## _FIRMWARE_BASENAME } | ||||||
|  |   | ||||||
|  | -int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev, | ||||||
|  | -			      struct brcmf_firmware_mapping mapping_table[], | ||||||
|  | -			      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 { | ||||||
| @@ -0,0 +1,44 @@ | |||||||
|  | From bf291b7247e53f52a4236c0b55a5df046d6177df Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Arend Van Spriel <arend.vanspriel@broadcom.com> | ||||||
|  | Date: Thu, 22 Mar 2018 21:28:30 +0100 | ||||||
|  | Subject: [PATCH] brcmfmac: get rid of brcmf_fw_get_full_name() | ||||||
|  |  | ||||||
|  | The function was pretty minimal and now it is called only from one | ||||||
|  | place so just get rid of it. | ||||||
|  |  | ||||||
|  | Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com> | ||||||
|  | Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||||
|  | --- | ||||||
|  |  .../net/wireless/broadcom/brcm80211/brcmfmac/firmware.c    | 14 ++++---------- | ||||||
|  |  1 file changed, 4 insertions(+), 10 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||||
|  | @@ -628,13 +628,6 @@ int brcmf_fw_get_firmwares(struct device | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -static void brcmf_fw_get_full_name(char fw_name[BRCMF_FW_NAME_LEN], | ||||||
|  | -				   const char *fw_base, const char *extension) | ||||||
|  | -{ | ||||||
|  | -	strlcat(fw_name, fw_base, BRCMF_FW_NAME_LEN); | ||||||
|  | -	strlcat(fw_name, extension, BRCMF_FW_NAME_LEN); | ||||||
|  | -} | ||||||
|  | - | ||||||
|  |  struct brcmf_fw_request * | ||||||
|  |  brcmf_fw_alloc_request(u32 chip, u32 chiprev, | ||||||
|  |  		       struct brcmf_firmware_mapping mapping_table[], | ||||||
|  | @@ -685,9 +678,10 @@ brcmf_fw_alloc_request(u32 chip, u32 chi | ||||||
|  |  					BRCMF_FW_NAME_LEN); | ||||||
|  |  			} | ||||||
|  |  		} | ||||||
|  | -		brcmf_fw_get_full_name(fwnames[j].path, | ||||||
|  | -				       mapping_table[i].fw_base, | ||||||
|  | -				       fwnames[j].extension); | ||||||
|  | +		strlcat(fwnames[j].path, mapping_table[i].fw_base, | ||||||
|  | +			BRCMF_FW_NAME_LEN); | ||||||
|  | +		strlcat(fwnames[j].path, fwnames[j].extension, | ||||||
|  | +			BRCMF_FW_NAME_LEN); | ||||||
|  |  		fwreq->items[j].path = fwnames[j].path; | ||||||
|  |  	} | ||||||
|  |   | ||||||
| @@ -0,0 +1,23 @@ | |||||||
|  | From 48eaee3f272a5bfe6986d07c51f6975d3c2f74d1 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Arend Van Spriel <arend.vanspriel@broadcom.com> | ||||||
|  | Date: Thu, 22 Mar 2018 21:28:31 +0100 | ||||||
|  | Subject: [PATCH] brcmfmac: add kerneldoc for struct brcmf_bus::msgbuf | ||||||
|  |  | ||||||
|  | This field did not have kerneldoc description so adding it now. | ||||||
|  |  | ||||||
|  | Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com> | ||||||
|  | Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||||
|  | --- | ||||||
|  |  drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 1 + | ||||||
|  |  1 file changed, 1 insertion(+) | ||||||
|  |  | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | ||||||
|  | @@ -140,6 +140,7 @@ struct brcmf_bus_stats { | ||||||
|  |   * @always_use_fws_queue: bus wants use queue also when fwsignal is inactive. | ||||||
|  |   * @wowl_supported: is wowl supported by bus driver. | ||||||
|  |   * @chiprev: revision of the dongle chip. | ||||||
|  | + * @msgbuf: msgbuf protocol parameters provided by bus layer. | ||||||
|  |   */ | ||||||
|  |  struct brcmf_bus { | ||||||
|  |  	union { | ||||||
| @@ -0,0 +1,81 @@ | |||||||
|  | From 0b5c0305e57ca940713bcb2b202fd2b412c62f31 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Arend Van Spriel <arend.vanspriel@broadcom.com> | ||||||
|  | Date: Tue, 3 Apr 2018 10:18:15 +0200 | ||||||
|  | Subject: [PATCH] brcmfmac: fix firmware request processing if nvram load fails | ||||||
|  |  | ||||||
|  | When nvram loading fails a double free occurred. Fix this and reorg the | ||||||
|  | code a little. | ||||||
|  |  | ||||||
|  | Fixes: d09ae51a4b67 ("brcmfmac: pass struct in brcmf_fw_get_firmwares()") | ||||||
|  | Reported-by: Dan Carpenter <dan.carpenter@oracle.com> | ||||||
|  | Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com> | ||||||
|  | Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||||
|  | --- | ||||||
|  |  .../broadcom/brcm80211/brcmfmac/firmware.c         | 36 ++++++++++++---------- | ||||||
|  |  1 file changed, 20 insertions(+), 16 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||||
|  | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||||
|  | @@ -459,7 +459,7 @@ static void brcmf_fw_free_request(struct | ||||||
|  |  	kfree(req); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) | ||||||
|  | +static int brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) | ||||||
|  |  { | ||||||
|  |  	struct brcmf_fw *fwctx = ctx; | ||||||
|  |  	struct brcmf_fw_item *cur; | ||||||
|  | @@ -498,13 +498,10 @@ static void brcmf_fw_request_nvram_done( | ||||||
|  |  	brcmf_dbg(TRACE, "nvram %p len %d\n", nvram, nvram_length); | ||||||
|  |  	cur->nv_data.data = nvram; | ||||||
|  |  	cur->nv_data.len = nvram_length; | ||||||
|  | -	return; | ||||||
|  | +	return 0; | ||||||
|  |   | ||||||
|  |  fail: | ||||||
|  | -	brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); | ||||||
|  | -	fwctx->done(fwctx->dev, -ENOENT, NULL); | ||||||
|  | -	brcmf_fw_free_request(fwctx->req); | ||||||
|  | -	kfree(fwctx); | ||||||
|  | +	return -ENOENT; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static int brcmf_fw_request_next_item(struct brcmf_fw *fwctx, bool async) | ||||||
|  | @@ -553,20 +550,27 @@ static void brcmf_fw_request_done(const | ||||||
|  |  	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)) { | ||||||
|  | +	if (!fw) | ||||||
|  |  		ret = -ENOENT; | ||||||
|  | + | ||||||
|  | +	switch (cur->type) { | ||||||
|  | +	case BRCMF_FW_TYPE_NVRAM: | ||||||
|  | +		ret = brcmf_fw_request_nvram_done(fw, fwctx); | ||||||
|  | +		break; | ||||||
|  | +	case BRCMF_FW_TYPE_BINARY: | ||||||
|  | +		cur->binary = fw; | ||||||
|  | +		break; | ||||||
|  | +	default: | ||||||
|  | +		/* something fishy here so bail out early */ | ||||||
|  | +		brcmf_err("unknown fw type: %d\n", cur->type); | ||||||
|  | +		release_firmware(fw); | ||||||
|  | +		ret = -EINVAL; | ||||||
|  |  		goto fail; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | +	if (ret < 0 && !(cur->flags & BRCMF_FW_REQF_OPTIONAL)) | ||||||
|  | +		goto fail; | ||||||
|  | + | ||||||
|  |  	do { | ||||||
|  |  		if (++fwctx->curpos == fwctx->req->n_items) { | ||||||
|  |  			ret = 0; | ||||||
| @@ -23,66 +23,44 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | |||||||
|  } |  } | ||||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||||
| @@ -445,6 +445,7 @@ struct brcmf_fw { | @@ -441,6 +441,7 @@ struct brcmf_fw { | ||||||
|  	u16 bus_nr; |  	struct brcmf_fw_request *req; | ||||||
|  	void (*done)(struct device *dev, int err, const struct firmware *fw, |  	u32 curpos; | ||||||
|  		     void *nvram_image, u32 nvram_len); |  	void (*done)(struct device *dev, int err, struct brcmf_fw_request *req); | ||||||
| +	struct completion *completion; | +	struct completion *completion; | ||||||
|  }; |  }; | ||||||
|   |   | ||||||
|  static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) |  static void brcmf_fw_request_done(const struct firmware *fw, void *ctx); | ||||||
| @@ -479,6 +480,8 @@ static void brcmf_fw_request_nvram_done( | @@ -589,6 +590,8 @@ fail: | ||||||
|  		goto fail; |  	fwctx->req = NULL; | ||||||
|   |  | ||||||
|  	fwctx->done(fwctx->dev, 0, fwctx->code, nvram, nvram_length); |  | ||||||
| +	if (fwctx->completion) |  | ||||||
| +		complete(fwctx->completion); |  | ||||||
|  	kfree(fwctx); |  | ||||||
|  	return; |  | ||||||
|   |  | ||||||
| @@ -486,6 +489,8 @@ fail: |  | ||||||
|  	brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); |  | ||||||
|  	release_firmware(fwctx->code); |  | ||||||
|  	fwctx->done(fwctx->dev, -ENOENT, NULL, NULL, 0); |  | ||||||
| +	if (fwctx->completion) |  | ||||||
| +		complete(fwctx->completion); |  | ||||||
|  	kfree(fwctx); |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| @@ -517,6 +522,8 @@ fail: |  | ||||||
|  	brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); |  | ||||||
|  done: |  done: | ||||||
|  	fwctx->done(fwctx->dev, ret, fw, NULL, 0); |  	fwctx->done(fwctx->dev, ret, fwctx->req); | ||||||
| +	if (fwctx->completion) | +	if (fwctx->completion) | ||||||
| +		complete(fwctx->completion); | +		complete(fwctx->completion); | ||||||
|  	kfree(fwctx); |  	kfree(fwctx); | ||||||
|  } |  } | ||||||
|   |   | ||||||
| @@ -528,6 +535,8 @@ int brcmf_fw_get_firmwares_pcie(struct d | @@ -612,6 +615,8 @@ int brcmf_fw_get_firmwares(struct device | ||||||
|  				u16 domain_nr, u16 bus_nr) |  					 struct brcmf_fw_request *req)) | ||||||
|  { |  { | ||||||
|  	struct brcmf_fw *fwctx; |  	struct brcmf_fw *fwctx; | ||||||
| +	struct completion completion; | +	struct completion completion; | ||||||
| +	int err; | +	int err; | ||||||
|   |   | ||||||
|  	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev)); |  	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev)); | ||||||
|  	if (!fw_cb || !code) |  	if (!fw_cb) | ||||||
| @@ -548,9 +557,17 @@ int brcmf_fw_get_firmwares_pcie(struct d | @@ -628,7 +633,14 @@ int brcmf_fw_get_firmwares(struct device | ||||||
|  	fwctx->domain_nr = domain_nr; |  	fwctx->req = req; | ||||||
|  	fwctx->bus_nr = bus_nr; |  	fwctx->done = fw_cb; | ||||||
|   |   | ||||||
| -	return request_firmware_nowait(THIS_MODULE, true, code, dev, |  | ||||||
| +	init_completion(&completion); | +	init_completion(&completion); | ||||||
| +	fwctx->completion = &completion; | +	fwctx->completion = &completion; | ||||||
| + | + | ||||||
| +	err = request_firmware_nowait(THIS_MODULE, true, code, dev, |  	brcmf_fw_request_next_item(fwctx, true); | ||||||
|  				       GFP_KERNEL, fwctx, | + | ||||||
|  				       brcmf_fw_request_code_done); | +	wait_for_completion_timeout(fwctx->completion, msecs_to_jiffies(5000)); | ||||||
| +	if (!err) |  | ||||||
| +		wait_for_completion_timeout(fwctx->completion, |  | ||||||
| +					    msecs_to_jiffies(5000)); |  | ||||||
| +	fwctx->completion = NULL; | +	fwctx->completion = NULL; | ||||||
| +	return err; | + | ||||||
|  |  	return 0; | ||||||
|  } |  } | ||||||
|   |   | ||||||
|  int brcmf_fw_get_firmwares(struct device *dev, u16 flags, |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Rafał Miłecki
					Rafał Miłecki