diff options
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.patch | 83 |
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) |