84 lines
3 KiB
Diff
84 lines
3 KiB
Diff
|
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)
|