mac80211: backport today's brcmfmac changes
This fixes various problems with parsing platform NVRAM. It's required to get BCM43602 working in most cases. Signed-off-by: Rafał Miłecki <zajec5@gmail.com> SVN-Revision: 45802
This commit is contained in:
		| @@ -0,0 +1,102 @@ | ||||
| From: Arend van Spriel <arend@broadcom.com> | ||||
| Date: Tue, 26 May 2015 13:19:46 +0200 | ||||
| Subject: [PATCH] brcmfmac: avoid null pointer access when | ||||
|  brcmf_msgbuf_get_pktid() fails | ||||
|  | ||||
| The function brcmf_msgbuf_get_pktid() may return a NULL pointer so | ||||
| the callers should check the return pointer before accessing it to | ||||
| avoid the crash below (see [1]): | ||||
|  | ||||
| brcmfmac: brcmf_msgbuf_get_pktid: Invalid packet id 273 (not in use) | ||||
| BUG: unable to handle kernel NULL pointer dereference at 0000000000000080 | ||||
| IP: [<ffffffff8145b225>] skb_pull+0x5/0x50 | ||||
| PGD 0 | ||||
| Oops: 0000 [#1] PREEMPT SMP | ||||
| Modules linked in: pci_stub vboxpci(O) vboxnetflt(O) vboxnetadp(O) vboxdrv(O) | ||||
|  snd_hda_codec_hdmi bnep mousedev hid_generic ushwmon msr ext4 crc16 mbcache | ||||
|  jbd2 sd_mod uas usb_storage ahci libahci libata scsi_mod xhci_pci xhci_hcd | ||||
|  usbcore usb_common | ||||
| CPU: 0 PID: 1661 Comm: irq/61-brcmf_pc Tainted: G O    4.0.1-MacbookPro-ARCH #1 | ||||
| Hardware name: Apple Inc. MacBookPro12,1/Mac-E43C1C25D4880AD6, | ||||
|  BIOS MBP121.88Z.0167.B02.1503241251 03/24/2015 | ||||
| task: ffff880264203cc0 ti: ffff88025ffe4000 task.ti: ffff88025ffe4000 | ||||
| RIP: 0010:[<ffffffff8145b225>]  [<ffffffff8145b225>] skb_pull+0x5/0x50 | ||||
| RSP: 0018:ffff88025ffe7d40  EFLAGS: 00010202 | ||||
| RAX: 0000000000000000 RBX: ffff88008a33c000 RCX: 0000000000000044 | ||||
| RDX: 0000000000000000 RSI: 000000000000004a RDI: 0000000000000000 | ||||
| RBP: ffff88025ffe7da8 R08: 0000000000000096 R09: 000000000000004a | ||||
| R10: 0000000000000000 R11: 000000000000048e R12: ffff88025ff14f00 | ||||
| R13: 0000000000000000 R14: ffff880263b48200 R15: ffff88008a33c000 | ||||
| FS:  0000000000000000(0000) GS:ffff88026ec00000(0000) knlGS:0000000000000000 | ||||
| CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 | ||||
| CR2: 0000000000000080 CR3: 000000000180b000 CR4: 00000000003407f0 | ||||
| Stack: | ||||
|  ffffffffa06aed74 ffff88025ffe7dc8 ffff880263b48270 ffff880263b48278 | ||||
|  05ea88020000004a 0002ffff81014635 000000001720b2f6 ffff88026ec116c0 | ||||
|  ffff880263b48200 0000000000010000 ffff880263b4ae00 ffff880264203cc0 | ||||
| Call Trace: | ||||
|  [<ffffffffa06aed74>] ? brcmf_msgbuf_process_rx+0x404/0x480 [brcmfmac] | ||||
|  [<ffffffff810cea60>] ? irq_finalize_oneshot.part.30+0xf0/0xf0 | ||||
|  [<ffffffffa06afb55>] brcmf_proto_msgbuf_rx_trigger+0x35/0xf0 [brcmfmac] | ||||
|  [<ffffffffa06baf2a>] brcmf_pcie_isr_thread_v2+0x8a/0x130 [brcmfmac] | ||||
|  [<ffffffff810cea80>] irq_thread_fn+0x20/0x50 | ||||
|  [<ffffffff810ceddf>] irq_thread+0x13f/0x170 | ||||
|  [<ffffffff810cebf0>] ? wake_threads_waitq+0x30/0x30 | ||||
|  [<ffffffff810ceca0>] ? irq_thread_dtor+0xb0/0xb0 | ||||
|  [<ffffffff81092a08>] kthread+0xd8/0xf0 | ||||
|  [<ffffffff81092930>] ? kthread_create_on_node+0x1c0/0x1c0 | ||||
|  [<ffffffff8156d898>] ret_from_fork+0x58/0x90 | ||||
|  [<ffffffff81092930>] ? kthread_create_on_node+0x1c0/0x1c0 | ||||
| Code: 01 83 e2 f7 88 50 01 48 83 c4 08 5b 5d f3 c3 0f 1f 80 00 00 00 00 83 e2 | ||||
|  f7 88 50 01 c3 66 0f 1f 84 00 00 00 00 00 0f 1f | ||||
| RIP  [<ffffffff8145b225>] skb_pull+0x5/0x50 | ||||
|  RSP <ffff88025ffe7d40> | ||||
| CR2: 0000000000000080 | ||||
| ---[ end trace b074c0f90e7c997d ]--- | ||||
|  | ||||
| [1] http://mid.gmane.org/20150430193259.GA5630@googlemail.com | ||||
|  | ||||
| Cc: <stable@vger.kernel.org> # v3.18, v3.19, v4.0, v4.1 | ||||
| Reported-by: Michael Hornung <mhornung.linux@gmail.com> | ||||
| Reviewed-by: Hante Meuleman <meuleman@broadcom.com> | ||||
| Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> | ||||
| Signed-off-by: Arend van Spriel <arend@broadcom.com> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | ||||
| +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | ||||
| @@ -500,11 +500,9 @@ static int brcmf_msgbuf_query_dcmd(struc | ||||
|  				     msgbuf->rx_pktids, | ||||
|  				     msgbuf->ioctl_resp_pktid); | ||||
|  	if (msgbuf->ioctl_resp_ret_len != 0) { | ||||
| -		if (!skb) { | ||||
| -			brcmf_err("Invalid packet id idx recv'd %d\n", | ||||
| -				  msgbuf->ioctl_resp_pktid); | ||||
| +		if (!skb) | ||||
|  			return -EBADF; | ||||
| -		} | ||||
| + | ||||
|  		memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ? | ||||
|  				       len : msgbuf->ioctl_resp_ret_len); | ||||
|  	} | ||||
| @@ -866,10 +864,8 @@ brcmf_msgbuf_process_txstatus(struct brc | ||||
|  	flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS; | ||||
|  	skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, | ||||
|  				     msgbuf->tx_pktids, idx); | ||||
| -	if (!skb) { | ||||
| -		brcmf_err("Invalid packet id idx recv'd %d\n", idx); | ||||
| +	if (!skb) | ||||
|  		return; | ||||
| -	} | ||||
|   | ||||
|  	set_bit(flowid, msgbuf->txstatus_done_map); | ||||
|  	commonring = msgbuf->flowrings[flowid]; | ||||
| @@ -1148,6 +1144,8 @@ brcmf_msgbuf_process_rx_complete(struct | ||||
|   | ||||
|  	skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, | ||||
|  				     msgbuf->rx_pktids, idx); | ||||
| +	if (!skb) | ||||
| +		return; | ||||
|   | ||||
|  	if (data_offset) | ||||
|  		skb_pull(skb, data_offset); | ||||
| @@ -0,0 +1,63 @@ | ||||
| From: Arend van Spriel <arend@broadcom.com> | ||||
| Date: Wed, 27 May 2015 19:31:41 +0200 | ||||
| Subject: [PATCH] brcmfmac: fix invalid access to struct acpi_device fields | ||||
|  | ||||
| The fields of struct acpi_device are only known when CONFIG_ACPI is | ||||
| defined. Fix this by using a helper function. This will resolve the | ||||
| issue found in linux-next: | ||||
|  | ||||
|  ../brcmfmac/bcmsdh.c: In function 'brcmf_ops_sdio_probe': | ||||
|  ../brcmfmac/bcmsdh.c:1139:7: error: dereferencing pointer to incomplete type | ||||
|    adev->flags.power_manageable = 0; | ||||
|        ^ | ||||
|  | ||||
| Fixes: f0992ace680c ("brcmfmac: prohibit ACPI power management ...") | ||||
| Cc: Fu, Zhonghui <zhonghui.fu@linux.intel.com> | ||||
| Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> | ||||
| Signed-off-by: Arend van Spriel <arend@broadcom.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | ||||
| +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | ||||
| @@ -1117,6 +1117,18 @@ MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_id | ||||
|  static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata; | ||||
|   | ||||
|   | ||||
| +static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev, | ||||
| +						  int val) | ||||
| +{ | ||||
| +#if IS_ENABLED(CONFIG_ACPI) | ||||
| +	struct acpi_device *adev; | ||||
| + | ||||
| +	adev = ACPI_COMPANION(dev); | ||||
| +	if (adev) | ||||
| +		adev->flags.power_manageable = 0; | ||||
| +#endif | ||||
| +} | ||||
| + | ||||
|  static int brcmf_ops_sdio_probe(struct sdio_func *func, | ||||
|  				const struct sdio_device_id *id) | ||||
|  { | ||||
| @@ -1124,7 +1136,6 @@ static int brcmf_ops_sdio_probe(struct s | ||||
|  	struct brcmf_sdio_dev *sdiodev; | ||||
|  	struct brcmf_bus *bus_if; | ||||
|  	struct device *dev; | ||||
| -	struct acpi_device *adev; | ||||
|   | ||||
|  	brcmf_dbg(SDIO, "Enter\n"); | ||||
|  	brcmf_dbg(SDIO, "Class=%x\n", func->class); | ||||
| @@ -1132,11 +1143,9 @@ static int brcmf_ops_sdio_probe(struct s | ||||
|  	brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); | ||||
|  	brcmf_dbg(SDIO, "Function#: %d\n", func->num); | ||||
|   | ||||
| -	/* prohibit ACPI power management for this device */ | ||||
|  	dev = &func->dev; | ||||
| -	adev = ACPI_COMPANION(dev); | ||||
| -	if (adev) | ||||
| -		adev->flags.power_manageable = 0; | ||||
| +	/* prohibit ACPI power management for this device */ | ||||
| +	brcmf_sdiod_acpi_set_power_manageable(dev, 0); | ||||
|   | ||||
|  	/* Consume func num 1 but dont do anything with it. */ | ||||
|  	if (func->num == 1) | ||||
| @@ -0,0 +1,56 @@ | ||||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Date: Wed, 20 May 2015 09:34:21 +0200 | ||||
| Subject: [PATCH] brcmfmac: simplify check stripping v2 NVRAM | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| Comparing NVRAM entry with a full filtering string is simpler than | ||||
| comparing it with a short prefix and then checking random chars at magic | ||||
| offsets. The cost of snprintf relatively low, we execute it just once. | ||||
| Tested on BCM43602 with NVRAM hacked to use V2 format. | ||||
|  | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c | ||||
| +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c | ||||
| @@ -25,7 +25,7 @@ | ||||
|   | ||||
|  #define BRCMF_FW_MAX_NVRAM_SIZE			64000 | ||||
|  #define BRCMF_FW_NVRAM_DEVPATH_LEN		19	/* devpath0=pcie/1/4/ */ | ||||
| -#define BRCMF_FW_NVRAM_PCIEDEV_LEN		9	/* pcie/1/4/ */ | ||||
| +#define BRCMF_FW_NVRAM_PCIEDEV_LEN		10	/* pcie/1/4/ + \0 */ | ||||
|   | ||||
|  char brcmf_firmware_path[BRCMF_FW_PATH_LEN]; | ||||
|  module_param_string(firmware_path, brcmf_firmware_path, | ||||
| @@ -297,6 +297,8 @@ fail: | ||||
|  static void brcmf_fw_strip_multi_v2(struct nvram_parser *nvp, u16 domain_nr, | ||||
|  				    u16 bus_nr) | ||||
|  { | ||||
| +	char prefix[BRCMF_FW_NVRAM_PCIEDEV_LEN]; | ||||
| +	size_t len; | ||||
|  	u32 i, j; | ||||
|  	u8 *nvram; | ||||
|   | ||||
| @@ -308,14 +310,13 @@ static void brcmf_fw_strip_multi_v2(stru | ||||
|  	 * Valid entries are of type pcie/X/Y/ where X = domain_nr and | ||||
|  	 * Y = bus_nr. | ||||
|  	 */ | ||||
| +	snprintf(prefix, sizeof(prefix), "pcie/%d/%d/", domain_nr, bus_nr); | ||||
| +	len = strlen(prefix); | ||||
|  	i = 0; | ||||
|  	j = 0; | ||||
| -	while (i < nvp->nvram_len - BRCMF_FW_NVRAM_PCIEDEV_LEN) { | ||||
| -		if ((strncmp(&nvp->nvram[i], "pcie/", 5) == 0) && | ||||
| -		    (nvp->nvram[i + 6] == '/') && (nvp->nvram[i + 8] == '/') && | ||||
| -		    ((nvp->nvram[i + 5] - '0') == domain_nr) && | ||||
| -		    ((nvp->nvram[i + 7] - '0') == bus_nr)) { | ||||
| -			i += BRCMF_FW_NVRAM_PCIEDEV_LEN; | ||||
| +	while (i < nvp->nvram_len - len) { | ||||
| +		if (strncmp(&nvp->nvram[i], prefix, len) == 0) { | ||||
| +			i += len; | ||||
|  			while (nvp->nvram[i] != 0) { | ||||
|  				nvram[j] = nvp->nvram[i]; | ||||
|  				i++; | ||||
| @@ -0,0 +1,57 @@ | ||||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Date: Wed, 20 May 2015 11:01:08 +0200 | ||||
| Subject: [PATCH] brcmfmac: simplify check finding NVRAM v1 device path | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| With a simple use of snprintf and small buffer we can compare NVRAM | ||||
| entry value with a full string. This way we avoid checking random chars | ||||
| at magic offsets. | ||||
| Tested on BCM43602 with NVRAM hacked to use v1 format. | ||||
|  | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c | ||||
| +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c | ||||
| @@ -222,6 +222,10 @@ static int brcmf_init_nvram_parser(struc | ||||
|  static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr, | ||||
|  				    u16 bus_nr) | ||||
|  { | ||||
| +	/* Device path with a leading '=' key-value separator */ | ||||
| +	char pcie_path[] = "=pcie/?/?"; | ||||
| +	size_t pcie_len; | ||||
| + | ||||
|  	u32 i, j; | ||||
|  	bool found; | ||||
|  	u8 *nvram; | ||||
| @@ -238,6 +242,9 @@ static void brcmf_fw_strip_multi_v1(stru | ||||
|  	/* First search for the devpathX and see if it is the configuration | ||||
|  	 * for domain_nr/bus_nr. Search complete nvp | ||||
|  	 */ | ||||
| +	snprintf(pcie_path, sizeof(pcie_path), "=pcie/%d/%d", domain_nr, | ||||
| +		 bus_nr); | ||||
| +	pcie_len = strlen(pcie_path); | ||||
|  	found = false; | ||||
|  	i = 0; | ||||
|  	while (i < nvp->nvram_len - BRCMF_FW_NVRAM_DEVPATH_LEN) { | ||||
| @@ -245,13 +252,10 @@ static void brcmf_fw_strip_multi_v1(stru | ||||
|  		 * Y = domain_nr, Z = bus_nr, X = virtual ID | ||||
|  		 */ | ||||
|  		if ((strncmp(&nvp->nvram[i], "devpath", 7) == 0) && | ||||
| -		    (strncmp(&nvp->nvram[i + 8], "=pcie/", 6) == 0)) { | ||||
| -			if (((nvp->nvram[i + 14] - '0') == domain_nr) && | ||||
| -			    ((nvp->nvram[i + 16] - '0') == bus_nr)) { | ||||
| -				id = nvp->nvram[i + 7] - '0'; | ||||
| -				found = true; | ||||
| -				break; | ||||
| -			} | ||||
| +		    (strncmp(&nvp->nvram[i + 8], pcie_path, pcie_len) == 0)) { | ||||
| +			id = nvp->nvram[i + 7] - '0'; | ||||
| +			found = true; | ||||
| +			break; | ||||
|  		} | ||||
|  		while (nvp->nvram[i] != 0) | ||||
|  			i++; | ||||
| @@ -0,0 +1,45 @@ | ||||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Date: Wed, 20 May 2015 13:59:54 +0200 | ||||
| Subject: [PATCH] brcmfmac: treat \0 as end of comment when parsing NVRAM | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| This fixes brcmfmac dealing with NVRAM coming from platform e.g. from a | ||||
| flash MTD partition. In such cases entries are separated by \0 instead | ||||
| of \n which caused ignoring whole content after the first "comment". | ||||
| While platform NVRAM doesn't usually contain comments, we switch to | ||||
| COMMENT state after e.g. finding an unexpected char in key name. | ||||
|  | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c | ||||
| +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c | ||||
| @@ -162,17 +162,20 @@ brcmf_nvram_handle_value(struct nvram_pa | ||||
|  static enum nvram_parser_state | ||||
|  brcmf_nvram_handle_comment(struct nvram_parser *nvp) | ||||
|  { | ||||
| -	char *eol, *sol; | ||||
| +	char *eoc, *sol; | ||||
|   | ||||
|  	sol = (char *)&nvp->fwnv->data[nvp->pos]; | ||||
| -	eol = strchr(sol, '\n'); | ||||
| -	if (eol == NULL) | ||||
| -		return END; | ||||
| +	eoc = strchr(sol, '\n'); | ||||
| +	if (!eoc) { | ||||
| +		eoc = strchr(sol, '\0'); | ||||
| +		if (!eoc) | ||||
| +			return END; | ||||
| +	} | ||||
|   | ||||
|  	/* eat all moving to next line */ | ||||
|  	nvp->line++; | ||||
|  	nvp->column = 1; | ||||
| -	nvp->pos += (eol - sol) + 1; | ||||
| +	nvp->pos += (eoc - sol) + 1; | ||||
|  	return IDLE; | ||||
|  } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Rafał Miłecki
					Rafał Miłecki