From b3ff29aed36fc4e2a39ead966f37203a467e1873 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 17 Jun 2016 06:23:06 +0000 Subject: [PATCH] mac80211: brcmfmac: backport fixes for 4.7 and 4.8 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki SVN-Revision: 49380 --- ...lback-for-devices-that-do-not-report.patch | 52 +++++++++++ ..._type_trans-back-for-PCIe-full-dongl.patch | 87 ++++++++++++++++++ ...-the-wrong-variable-in-brcmf_rx_hdrp.patch | 39 ++++++++ ...ix-kernel-oops-in-failed-chip_attach.patch | 88 +++++++++++++++++++ ...x-did-not-remove-int-handler-warning.patch | 83 +++++++++++++++++ ...fmac-add-missing-eth_type_trans-call.patch | 26 ------ ...63-brcmfmac-Disable-power-management.patch | 2 +- 7 files changed, 350 insertions(+), 27 deletions(-) create mode 100644 package/kernel/mac80211/patches/350-0001-brcmfmac-add-fallback-for-devices-that-do-not-report.patch create mode 100644 package/kernel/mac80211/patches/350-0002-brcmfmac-add-eth_type_trans-back-for-PCIe-full-dongl.patch create mode 100644 package/kernel/mac80211/patches/351-0001-brcmfmac-testing-the-wrong-variable-in-brcmf_rx_hdrp.patch create mode 100644 package/kernel/mac80211/patches/351-0003-brcmfmac-Fix-kernel-oops-in-failed-chip_attach.patch create mode 100644 package/kernel/mac80211/patches/351-0004-brcmfmac-Fix-did-not-remove-int-handler-warning.patch delete mode 100644 package/kernel/mac80211/patches/860-brcmfmac-add-missing-eth_type_trans-call.patch diff --git a/package/kernel/mac80211/patches/350-0001-brcmfmac-add-fallback-for-devices-that-do-not-report.patch b/package/kernel/mac80211/patches/350-0001-brcmfmac-add-fallback-for-devices-that-do-not-report.patch new file mode 100644 index 0000000000..7b299d54d2 --- /dev/null +++ b/package/kernel/mac80211/patches/350-0001-brcmfmac-add-fallback-for-devices-that-do-not-report.patch @@ -0,0 +1,52 @@ +From: Jaap Jan Meijer +Date: Thu, 12 May 2016 18:25:08 +0200 +Subject: [PATCH] brcmfmac: add fallback for devices that do not report + per-chain values + +If brcmf_cfg80211_get_station fails to determine the RSSI from the +per-chain values get the value individually as a fallback. + +Fixes: 1f0dc59a6de9 ("brcmfmac: rework .get_station() callback") +Signed-off-by: Jaap Jan Meijer +Acked-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -2480,12 +2480,14 @@ brcmf_cfg80211_get_station(struct wiphy + const u8 *mac, struct station_info *sinfo) + { + struct brcmf_if *ifp = netdev_priv(ndev); ++ struct brcmf_scb_val_le scb_val; + s32 err = 0; + struct brcmf_sta_info_le sta_info_le; + u32 sta_flags; + u32 is_tdls_peer; + s32 total_rssi; + s32 count_rssi; ++ int rssi; + u32 i; + + brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac); +@@ -2569,6 +2571,20 @@ brcmf_cfg80211_get_station(struct wiphy + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + total_rssi /= count_rssi; + sinfo->signal = total_rssi; ++ } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED, ++ &ifp->vif->sme_state)) { ++ memset(&scb_val, 0, sizeof(scb_val)); ++ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, ++ &scb_val, sizeof(scb_val)); ++ if (err) { ++ brcmf_err("Could not get rssi (%d)\n", err); ++ goto done; ++ } else { ++ rssi = le32_to_cpu(scb_val.val); ++ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); ++ sinfo->signal = rssi; ++ brcmf_dbg(CONN, "RSSI %d dBm\n", rssi); ++ } + } + } + done: diff --git a/package/kernel/mac80211/patches/350-0002-brcmfmac-add-eth_type_trans-back-for-PCIe-full-dongl.patch b/package/kernel/mac80211/patches/350-0002-brcmfmac-add-eth_type_trans-back-for-PCIe-full-dongl.patch new file mode 100644 index 0000000000..db8112d399 --- /dev/null +++ b/package/kernel/mac80211/patches/350-0002-brcmfmac-add-eth_type_trans-back-for-PCIe-full-dongl.patch @@ -0,0 +1,87 @@ +From: Franky Lin +Date: Thu, 2 Jun 2016 02:00:27 -0700 +Subject: [PATCH] brcmfmac: add eth_type_trans back for PCIe full dongle + +A regression was introduced in commit 9c349892ccc9 ("brcmfmac: revise +handling events in receive path") which moves eth_type_trans() call +to brcmf_rx_frame(). Msgbuf layer doesn't use brcmf_rx_frame() but invokes +brcmf_netif_rx() directly. In such case the Ethernet header was not +stripped out resulting in null pointer dereference in the networking +stack. + +BUG: unable to handle kernel NULL pointer dereference at 0000000000000048 +IP: [] enqueue_to_backlog+0x56/0x260 +PGD 0 +Oops: 0000 [#1] PREEMPT SMP +Modules linked in: fuse ipt_MASQUERADE nf_nat_masquerade_ipv4 +iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 xt_addrtype +[...] +rtsx_pci scsi_mod usbcore usb_common i8042 serio nvme nvme_core +CPU: 7 PID: 1340 Comm: irq/136-brcmf_p Not tainted 4.7.0-rc1-mainline #1 +Hardware name: Dell Inc. XPS 15 9550/0N7TVV, BIOS 01.02.00 04/07/2016 +task: ffff8804a0c5bd00 ti: ffff88049e124000 task.ti: ffff88049e124000 +RIP: 0010:[] [] +enqueue_to_backlog+0x56/0x260 +RSP: 0018:ffff88049e127ca0 EFLAGS: 00010046 +RAX: 0000000000000000 RBX: ffff8804bddd7c40 RCX: 000000000000002f +RDX: 0000000000000000 RSI: 0000000000000007 RDI: ffff8804bddd7d4c +RBP: ffff88049e127ce8 R08: 0000000000000000 R09: 0000000000000000 +R10: ffff8804bddd12c0 R11: 000000000000149e R12: 0000000000017c40 +R13: ffff88049e127d08 R14: ffff8804a9bd6d00 R15: ffff8804bddd7d4c +FS: 0000000000000000(0000) GS:ffff8804bddc0000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 0000000000000048 CR3: 0000000001806000 CR4: 00000000003406e0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +Stack: +ffff8804bdddad00 ffff8804ad089e00 0000000000000000 0000000000000282 +0000000000000000 ffff8804a9bd6d00 ffff8804a1b27e00 ffff8804a9bd6d00 +ffff88002ee88000 ffff88049e127d28 ffffffff814c3f3b ffffffff81311fc3 +Call Trace: +[] netif_rx_internal+0x4b/0x170 +[] ? swiotlb_tbl_unmap_single+0xf3/0x120 +[] netif_rx_ni+0x27/0xc0 +[] brcmf_netif_rx+0x49/0x70 [brcmfmac] +[] brcmf_msgbuf_process_rx+0x2b4/0x570 [brcmfmac] +[] ? __xen_set_pgd_hyper+0x57/0xd0 +[] ? irq_forced_thread_fn+0x70/0x70 +[] brcmf_proto_msgbuf_rx_trigger+0x31/0xe0 [brcmfmac] +[] brcmf_pcie_isr_thread+0x7f/0x110 [brcmfmac] +[] irq_thread_fn+0x20/0x50 +[] irq_thread+0x12d/0x1c0 +[] ? __schedule+0x2f5/0x7a0 +[] ? wake_threads_waitq+0x30/0x30 +[] ? irq_thread_dtor+0xb0/0xb0 +[] kthread+0xd8/0xf0 +[] ret_from_fork+0x1f/0x40 +[] ? kthread_worker_fn+0x170/0x170 +Code: 1c f5 60 9a 8e 81 9c 58 0f 1f 44 00 00 48 89 45 d0 fa 66 0f 1f +44 00 00 4c 8d bb 0c 01 00 00 4c 89 ff e8 5e 08 11 00 49 8b 56 20 <48> +8b 52 48 83 e2 01 74 10 8b 8b 08 01 00 00 8b 15 59 c5 42 00 +RIP [] enqueue_to_backlog+0x56/0x260 +RSP +CR2: 0000000000000048 + +Fixes: 9c349892ccc9 ("brcmfmac: revise handling events in receive path") +Reported-by: Rafal Milecki +Reported-by: Grey Christoforo +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Arend Van Spriel +Reviewed-by: Hante Meuleman +Signed-off-by: Franky Lin +[arend@broadcom.com: rephrased the commit message] +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +@@ -1157,6 +1157,8 @@ brcmf_msgbuf_process_rx_complete(struct + brcmu_pkt_buf_free_skb(skb); + return; + } ++ ++ skb->protocol = eth_type_trans(skb, ifp->ndev); + brcmf_netif_rx(ifp, skb); + } + diff --git a/package/kernel/mac80211/patches/351-0001-brcmfmac-testing-the-wrong-variable-in-brcmf_rx_hdrp.patch b/package/kernel/mac80211/patches/351-0001-brcmfmac-testing-the-wrong-variable-in-brcmf_rx_hdrp.patch new file mode 100644 index 0000000000..11c65a49ed --- /dev/null +++ b/package/kernel/mac80211/patches/351-0001-brcmfmac-testing-the-wrong-variable-in-brcmf_rx_hdrp.patch @@ -0,0 +1,39 @@ +From: Dan Carpenter +Date: Tue, 19 Apr 2016 07:25:43 -0700 +Subject: [PATCH] brcmfmac: testing the wrong variable in brcmf_rx_hdrpull() + +Smatch complains about this code: + + drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c:335 brcmf_rx_hdrpull() + error: we previously assumed '*ifp' could be null (see line 333) + +The problem is that we recently changed these from "ifp" to "*ifp" but +there was one that we didn't update. + +- if (ret || !ifp || !ifp->ndev) { ++ if (ret || !(*ifp) || !(*ifp)->ndev) { + if (ret != -ENODATA && ifp) + ^^^ +- ifp->stats.rx_errors++; ++ (*ifp)->stats.rx_errors++; + +I have updated it to *ifp as well. We always call this function is a +non-NULL "ifp" pointer, btw. + +Fixes: c462ebcdfe42 ('brcmfmac: create common function for handling brcmf_proto_hdrpull()') +Signed-off-by: Dan Carpenter +Acked-by: Arend van Spriel +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -331,7 +331,7 @@ static int brcmf_rx_hdrpull(struct brcmf + ret = brcmf_proto_hdrpull(drvr, true, skb, ifp); + + if (ret || !(*ifp) || !(*ifp)->ndev) { +- if (ret != -ENODATA && ifp) ++ if (ret != -ENODATA && *ifp) + (*ifp)->stats.rx_errors++; + brcmu_pkt_buf_free_skb(skb); + return -ENODATA; diff --git a/package/kernel/mac80211/patches/351-0003-brcmfmac-Fix-kernel-oops-in-failed-chip_attach.patch b/package/kernel/mac80211/patches/351-0003-brcmfmac-Fix-kernel-oops-in-failed-chip_attach.patch new file mode 100644 index 0000000000..59f1e42d4d --- /dev/null +++ b/package/kernel/mac80211/patches/351-0003-brcmfmac-Fix-kernel-oops-in-failed-chip_attach.patch @@ -0,0 +1,88 @@ +From: Christian Daudt +Date: Wed, 11 May 2016 15:06:48 -0700 +Subject: [PATCH] brcmfmac: Fix kernel oops in failed chip_attach + +When chip attach fails, brcmf_sdiod_intr_unregister is being called +but that is too early as sdiodev->settings has not been set yet +nor has brcmf_sdiod_intr_register been called. +Change to use oob_irq_requested + newly created sd_irq_requested +to decide on what to unregister at intr_unregister time. + +Steps to reproduce problem: +- modprobe brcmfmac using buggy FW +- rmmod brcmfmac +- modprobe brcmfmac again. + +If done with a buggy firmware, brcm_chip_attach will fail on the +2nd modprobe triggering the call to intr_unregister and the +kernel oops when attempting to de-reference sdiodev->settings->bus.sdio +which has not yet been set. + +Signed-off-by: Christian Daudt +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +@@ -166,6 +166,7 @@ int brcmf_sdiod_intr_register(struct brc + sdio_claim_irq(sdiodev->func[1], brcmf_sdiod_ib_irqhandler); + sdio_claim_irq(sdiodev->func[2], brcmf_sdiod_dummy_irqhandler); + sdio_release_host(sdiodev->func[1]); ++ sdiodev->sd_irq_requested = true; + } + + return 0; +@@ -173,27 +174,30 @@ int brcmf_sdiod_intr_register(struct brc + + int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) + { +- struct brcmfmac_sdio_pd *pdata; + +- brcmf_dbg(SDIO, "Entering\n"); ++ brcmf_dbg(SDIO, "Entering oob=%d sd=%d\n", ++ sdiodev->oob_irq_requested, ++ sdiodev->sd_irq_requested); + +- pdata = &sdiodev->settings->bus.sdio; +- if (pdata->oob_irq_supported) { ++ if (sdiodev->oob_irq_requested) { ++ struct brcmfmac_sdio_pd *pdata; ++ ++ pdata = &sdiodev->settings->bus.sdio; + sdio_claim_host(sdiodev->func[1]); + brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL); + brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL); + sdio_release_host(sdiodev->func[1]); + +- if (sdiodev->oob_irq_requested) { +- sdiodev->oob_irq_requested = false; +- if (sdiodev->irq_wake) { +- disable_irq_wake(pdata->oob_irq_nr); +- sdiodev->irq_wake = false; +- } +- free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev); +- sdiodev->irq_en = false; ++ sdiodev->oob_irq_requested = false; ++ if (sdiodev->irq_wake) { ++ disable_irq_wake(pdata->oob_irq_nr); ++ sdiodev->irq_wake = false; + } +- } else { ++ free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev); ++ sdiodev->irq_en = false; ++ } ++ ++ if (sdiodev->sd_irq_requested) { + sdio_claim_host(sdiodev->func[1]); + sdio_release_irq(sdiodev->func[2]); + sdio_release_irq(sdiodev->func[1]); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +@@ -186,6 +186,7 @@ struct brcmf_sdio_dev { + struct brcmf_bus *bus_if; + struct brcmf_mp_device *settings; + bool oob_irq_requested; ++ bool sd_irq_requested; + bool irq_en; /* irq enable flags */ + spinlock_t irq_en_lock; + bool irq_wake; /* irq wake enable flags */ diff --git a/package/kernel/mac80211/patches/351-0004-brcmfmac-Fix-did-not-remove-int-handler-warning.patch b/package/kernel/mac80211/patches/351-0004-brcmfmac-Fix-did-not-remove-int-handler-warning.patch new file mode 100644 index 0000000000..3aabf590bb --- /dev/null +++ b/package/kernel/mac80211/patches/351-0004-brcmfmac-Fix-did-not-remove-int-handler-warning.patch @@ -0,0 +1,83 @@ +From: Christian Daudt +Date: Wed, 11 May 2016 15:06:49 -0700 +Subject: [PATCH] brcmfmac: Fix 'did not remove int handler' warning + +brcmf_sdiod_intr_unregister call that removes both func1 and +func2 interrupt handlers only called when brcmf_ops_sdio_remove +is called for func 1 (which is the 2nd call) but sdio is expecting +it to be removed at the end of each sdio_remove call. +This is causing 'rmmod bcmrfmac' on a 4356-sdio chip to complain +with: +WARNING: driver brcmfmac did not remove its interrupt handler! + +The modification makes calling brcmf_sdiod_intr_unregister multiple +times harmless by clearing the variables that track if interrupt +handlers have been installed, and then calls it on every +brcmf_ops_sdio_remove call instead of just remove for func 1. + +Signed-off-by: Christian Daudt +Signed-off-by: Kalle Valo +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +@@ -172,7 +172,7 @@ int brcmf_sdiod_intr_register(struct brc + return 0; + } + +-int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) ++void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) + { + + brcmf_dbg(SDIO, "Entering oob=%d sd=%d\n", +@@ -195,6 +195,7 @@ int brcmf_sdiod_intr_unregister(struct b + } + free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev); + sdiodev->irq_en = false; ++ sdiodev->oob_irq_requested = false; + } + + if (sdiodev->sd_irq_requested) { +@@ -202,9 +203,8 @@ int brcmf_sdiod_intr_unregister(struct b + sdio_release_irq(sdiodev->func[2]); + sdio_release_irq(sdiodev->func[1]); + sdio_release_host(sdiodev->func[1]); ++ sdiodev->sd_irq_requested = false; + } +- +- return 0; + } + + void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev, +@@ -1200,12 +1200,17 @@ static void brcmf_ops_sdio_remove(struct + brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); + brcmf_dbg(SDIO, "Function: %d\n", func->num); + +- if (func->num != 1) +- return; +- + bus_if = dev_get_drvdata(&func->dev); + if (bus_if) { + sdiodev = bus_if->bus_priv.sdio; ++ ++ /* start by unregistering irqs */ ++ brcmf_sdiod_intr_unregister(sdiodev); ++ ++ if (func->num != 1) ++ return; ++ ++ /* only proceed with rest of cleanup if func 1 */ + brcmf_sdiod_remove(sdiodev); + + dev_set_drvdata(&sdiodev->func[1]->dev, NULL); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +@@ -294,7 +294,7 @@ struct sdpcmd_regs { + + /* Register/deregister interrupt handler. */ + int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev); +-int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev); ++void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev); + + /* sdio device register access interface */ + u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret); diff --git a/package/kernel/mac80211/patches/860-brcmfmac-add-missing-eth_type_trans-call.patch b/package/kernel/mac80211/patches/860-brcmfmac-add-missing-eth_type_trans-call.patch deleted file mode 100644 index 7100820710..0000000000 --- a/package/kernel/mac80211/patches/860-brcmfmac-add-missing-eth_type_trans-call.patch +++ /dev/null @@ -1,26 +0,0 @@ -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Subject: [PATCH] brcmfmac: add missing eth_type_trans call -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There are 2 protocols supported by brcmfmac and msgbuf one was missing a -proper skb setup before passing it to the netif. This was triggering -"NULL pointer dereference". - -Fixes: 9c349892ccc9 ("brcmfmac: revise handling events in receive path") -Signed-off-by: Rafał Miłecki ---- - ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c -@@ -1157,6 +1157,9 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf) - brcmu_pkt_buf_free_skb(skb); - return; - } -+ -+ skb->protocol = eth_type_trans(skb, ifp->ndev); -+ - brcmf_netif_rx(ifp, skb); - } - diff --git a/package/kernel/mac80211/patches/863-brcmfmac-Disable-power-management.patch b/package/kernel/mac80211/patches/863-brcmfmac-Disable-power-management.patch index 1615202d8e..a24601fba1 100644 --- a/package/kernel/mac80211/patches/863-brcmfmac-Disable-power-management.patch +++ b/package/kernel/mac80211/patches/863-brcmfmac-Disable-power-management.patch @@ -14,7 +14,7 @@ Signed-off-by: Phil Elwell --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -@@ -2651,6 +2651,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip +@@ -2667,6 +2667,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip * preference in cfg struct to apply this to * FW later while initializing the dongle */ -- 2.30.2