aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2015-03-06 12:40:40 -0500
committerKalle Valo <kvalo@codeaurora.org>2015-03-13 09:16:34 -0400
commit449e58b85c0051117bf8428777b4ae38e098506a (patch)
tree4f0466344d7064e452615daf3e3498621d1c4304
parentb441ba8dc34136dc418d85299757514c3a08913d (diff)
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>
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio.c37
1 files changed, 24 insertions, 13 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
index 161acd046451..c9a9ff191616 100644
--- 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_sdio *bus)
2700 if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && 2700 if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
2701 data_ok(bus)) { 2701 data_ok(bus)) {
2702 sdio_claim_host(bus->sdiodev->func[1]); 2702 sdio_claim_host(bus->sdiodev->func[1]);
2703 err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, 2703 if (bus->ctrl_frame_stat) {
2704 bus->ctrl_frame_len); 2704 err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
2705 bus->ctrl_frame_len);
2706 bus->ctrl_frame_err = err;
2707 bus->ctrl_frame_stat = false;
2708 }
2705 sdio_release_host(bus->sdiodev->func[1]); 2709 sdio_release_host(bus->sdiodev->func[1]);
2706 bus->ctrl_frame_err = err;
2707 bus->ctrl_frame_stat = false;
2708 brcmf_sdio_wait_event_wakeup(bus); 2710 brcmf_sdio_wait_event_wakeup(bus);
2709 } 2711 }
2710 /* Send queued frames (limit 1 if rx may still be pending) */ 2712 /* Send queued frames (limit 1 if rx may still be pending) */
@@ -2720,9 +2722,13 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
2720 brcmf_err("failed backplane access over SDIO, halting operation\n"); 2722 brcmf_err("failed backplane access over SDIO, halting operation\n");
2721 atomic_set(&bus->intstatus, 0); 2723 atomic_set(&bus->intstatus, 0);
2722 if (bus->ctrl_frame_stat) { 2724 if (bus->ctrl_frame_stat) {
2723 bus->ctrl_frame_err = -ENODEV; 2725 sdio_claim_host(bus->sdiodev->func[1]);
2724 bus->ctrl_frame_stat = false; 2726 if (bus->ctrl_frame_stat) {
2725 brcmf_sdio_wait_event_wakeup(bus); 2727 bus->ctrl_frame_err = -ENODEV;
2728 bus->ctrl_frame_stat = false;
2729 brcmf_sdio_wait_event_wakeup(bus);
2730 }
2731 sdio_release_host(bus->sdiodev->func[1]);
2726 } 2732 }
2727 } else if (atomic_read(&bus->intstatus) || 2733 } else if (atomic_read(&bus->intstatus) ||
2728 atomic_read(&bus->ipend) > 0 || 2734 atomic_read(&bus->ipend) > 0 ||
@@ -2930,15 +2936,20 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
2930 brcmf_sdio_trigger_dpc(bus); 2936 brcmf_sdio_trigger_dpc(bus);
2931 wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat, 2937 wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat,
2932 msecs_to_jiffies(CTL_DONE_TIMEOUT)); 2938 msecs_to_jiffies(CTL_DONE_TIMEOUT));
2933 2939 ret = 0;
2934 if (!bus->ctrl_frame_stat) { 2940 if (bus->ctrl_frame_stat) {
2941 sdio_claim_host(bus->sdiodev->func[1]);
2942 if (bus->ctrl_frame_stat) {
2943 brcmf_dbg(SDIO, "ctrl_frame timeout\n");
2944 bus->ctrl_frame_stat = false;
2945 ret = -ETIMEDOUT;
2946 }
2947 sdio_release_host(bus->sdiodev->func[1]);
2948 }
2949 if (!ret) {
2935 brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n", 2950 brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n",
2936 bus->ctrl_frame_err); 2951 bus->ctrl_frame_err);
2937 ret = bus->ctrl_frame_err; 2952 ret = bus->ctrl_frame_err;
2938 } else {
2939 brcmf_dbg(SDIO, "ctrl_frame timeout\n");
2940 bus->ctrl_frame_stat = false;
2941 ret = -ETIMEDOUT;
2942 } 2953 }
2943 2954
2944 if (ret) 2955 if (ret)