1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- From: Hante Meuleman <[email protected]>
- 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 <[email protected]>
- Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
- Reviewed-by: Pieter-Paul Giesberts <[email protected]>
- Reviewed-by: Daniel (Deognyoun) Kim <[email protected]>
- Signed-off-by: Hante Meuleman <[email protected]>
- Signed-off-by: Arend van Spriel <[email protected]>
- Signed-off-by: Kalle Valo <[email protected]>
- ---
- --- 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)
|