aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/337-brcmfmac-Fix-possible-race-condition.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel/mac80211/patches/337-brcmfmac-Fix-possible-race-condition.patch')
-rw-r--r--package/kernel/mac80211/patches/337-brcmfmac-Fix-possible-race-condition.patch83
1 files changed, 83 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/337-brcmfmac-Fix-possible-race-condition.patch b/package/kernel/mac80211/patches/337-brcmfmac-Fix-possible-race-condition.patch
new file mode 100644
index 0000000000..3a2de7a944
--- /dev/null
+++ b/package/kernel/mac80211/patches/337-brcmfmac-Fix-possible-race-condition.patch
@@ -0,0 +1,83 @@
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 6 Mar 2015 18:40:40 +0100
+Subject: [PATCH] brcmfmac: Fix possible race-condition.
+
+SDIO is using a "shared" variable to handoff ctl frames to DPC
+and to see when they are done. In a timeout situation this can
+lead to erroneous situation where DPC started to handle the ctl
+frame while the timeout expired. This patch will fix this by
+adding locking around the shared variable.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+@@ -2700,11 +2700,13 @@ static void brcmf_sdio_dpc(struct brcmf_
+ if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
+ data_ok(bus)) {
+ sdio_claim_host(bus->sdiodev->func[1]);
+- err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
+- bus->ctrl_frame_len);
++ if (bus->ctrl_frame_stat) {
++ err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
++ bus->ctrl_frame_len);
++ bus->ctrl_frame_err = err;
++ bus->ctrl_frame_stat = false;
++ }
+ sdio_release_host(bus->sdiodev->func[1]);
+- bus->ctrl_frame_err = err;
+- bus->ctrl_frame_stat = false;
+ brcmf_sdio_wait_event_wakeup(bus);
+ }
+ /* Send queued frames (limit 1 if rx may still be pending) */
+@@ -2720,9 +2722,13 @@ static void brcmf_sdio_dpc(struct brcmf_
+ brcmf_err("failed backplane access over SDIO, halting operation\n");
+ atomic_set(&bus->intstatus, 0);
+ if (bus->ctrl_frame_stat) {
+- bus->ctrl_frame_err = -ENODEV;
+- bus->ctrl_frame_stat = false;
+- brcmf_sdio_wait_event_wakeup(bus);
++ sdio_claim_host(bus->sdiodev->func[1]);
++ if (bus->ctrl_frame_stat) {
++ bus->ctrl_frame_err = -ENODEV;
++ bus->ctrl_frame_stat = false;
++ brcmf_sdio_wait_event_wakeup(bus);
++ }
++ sdio_release_host(bus->sdiodev->func[1]);
+ }
+ } else if (atomic_read(&bus->intstatus) ||
+ atomic_read(&bus->ipend) > 0 ||
+@@ -2930,15 +2936,20 @@ brcmf_sdio_bus_txctl(struct device *dev,
+ brcmf_sdio_trigger_dpc(bus);
+ wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat,
+ msecs_to_jiffies(CTL_DONE_TIMEOUT));
+-
+- if (!bus->ctrl_frame_stat) {
++ ret = 0;
++ if (bus->ctrl_frame_stat) {
++ sdio_claim_host(bus->sdiodev->func[1]);
++ if (bus->ctrl_frame_stat) {
++ brcmf_dbg(SDIO, "ctrl_frame timeout\n");
++ bus->ctrl_frame_stat = false;
++ ret = -ETIMEDOUT;
++ }
++ sdio_release_host(bus->sdiodev->func[1]);
++ }
++ if (!ret) {
+ brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n",
+ bus->ctrl_frame_err);
+ ret = bus->ctrl_frame_err;
+- } else {
+- brcmf_dbg(SDIO, "ctrl_frame timeout\n");
+- bus->ctrl_frame_stat = false;
+- ret = -ETIMEDOUT;
+ }
+
+ if (ret)