diff options
Diffstat (limited to 'package/kernel/mac80211/patches/337-0002-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch')
-rw-r--r-- | package/kernel/mac80211/patches/337-0002-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/337-0002-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch b/package/kernel/mac80211/patches/337-0002-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch new file mode 100644 index 0000000000..c419cc68f5 --- /dev/null +++ b/package/kernel/mac80211/patches/337-0002-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch @@ -0,0 +1,171 @@ +From: Hante Meuleman <meuleman@broadcom.com> +Date: Wed, 18 Mar 2015 13:25:22 +0100 +Subject: [PATCH] brcmfmac: Add necessary memory barriers for SDIO. + +SDIO uses a thread to handle all communication with the device, +for this data is exchanged between threads. This data needs proper +memory barriers to make sure that data "exchange" is going correct. + +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 +@@ -507,8 +507,8 @@ struct brcmf_sdio { + + struct workqueue_struct *brcmf_wq; + struct work_struct datawork; +- atomic_t dpc_tskcnt; +- atomic_t dpc_running; ++ bool dpc_triggered; ++ bool dpc_running; + + bool txoff; /* Transmit flow-controlled */ + struct brcmf_sdio_count sdcnt; +@@ -2713,6 +2713,7 @@ static void brcmf_sdio_dpc(struct brcmf_ + err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, + bus->ctrl_frame_len); + bus->ctrl_frame_err = err; ++ wmb(); + bus->ctrl_frame_stat = false; + } + sdio_release_host(bus->sdiodev->func[1]); +@@ -2734,6 +2735,7 @@ static void brcmf_sdio_dpc(struct brcmf_ + sdio_claim_host(bus->sdiodev->func[1]); + if (bus->ctrl_frame_stat) { + bus->ctrl_frame_err = -ENODEV; ++ wmb(); + bus->ctrl_frame_stat = false; + brcmf_sdio_wait_event_wakeup(bus); + } +@@ -2744,7 +2746,7 @@ static void brcmf_sdio_dpc(struct brcmf_ + (!atomic_read(&bus->fcstate) && + brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && + data_ok(bus))) { +- atomic_inc(&bus->dpc_tskcnt); ++ bus->dpc_triggered = true; + } + } + +@@ -2940,6 +2942,7 @@ brcmf_sdio_bus_txctl(struct device *dev, + /* Send from dpc */ + bus->ctrl_frame_buf = msg; + bus->ctrl_frame_len = msglen; ++ wmb(); + bus->ctrl_frame_stat = true; + + brcmf_sdio_trigger_dpc(bus); +@@ -2958,6 +2961,7 @@ brcmf_sdio_bus_txctl(struct device *dev, + if (!ret) { + brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n", + bus->ctrl_frame_err); ++ rmb(); + ret = bus->ctrl_frame_err; + } + +@@ -3526,8 +3530,8 @@ done: + + void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus) + { +- if (atomic_read(&bus->dpc_tskcnt) == 0) { +- atomic_inc(&bus->dpc_tskcnt); ++ if (!bus->dpc_triggered) { ++ bus->dpc_triggered = true; + queue_work(bus->brcmf_wq, &bus->datawork); + } + } +@@ -3558,7 +3562,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *b + if (!bus->intr) + brcmf_err("isr w/o interrupt configured!\n"); + +- atomic_inc(&bus->dpc_tskcnt); ++ bus->dpc_triggered = true; + queue_work(bus->brcmf_wq, &bus->datawork); + } + +@@ -3578,7 +3582,7 @@ static void brcmf_sdio_bus_watchdog(stru + if (!bus->intr || + (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) { + +- if (atomic_read(&bus->dpc_tskcnt) == 0) { ++ if (!bus->dpc_triggered) { + u8 devpend; + + sdio_claim_host(bus->sdiodev->func[1]); +@@ -3596,7 +3600,7 @@ static void brcmf_sdio_bus_watchdog(stru + bus->sdcnt.pollcnt++; + atomic_set(&bus->ipend, 1); + +- atomic_inc(&bus->dpc_tskcnt); ++ bus->dpc_triggered = true; + queue_work(bus->brcmf_wq, &bus->datawork); + } + } +@@ -3623,17 +3627,21 @@ static void brcmf_sdio_bus_watchdog(stru + #endif /* DEBUG */ + + /* On idle timeout clear activity flag and/or turn off clock */ +- if ((atomic_read(&bus->dpc_tskcnt) == 0) && +- (atomic_read(&bus->dpc_running) == 0) && +- (bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { +- bus->idlecount++; +- if (bus->idlecount > bus->idletime) { +- brcmf_dbg(SDIO, "idle\n"); +- sdio_claim_host(bus->sdiodev->func[1]); +- brcmf_sdio_wd_timer(bus, 0); ++ if (!bus->dpc_triggered) { ++ rmb(); ++ if ((!bus->dpc_running) && (bus->idletime > 0) && ++ (bus->clkstate == CLK_AVAIL)) { ++ bus->idlecount++; ++ if (bus->idlecount > bus->idletime) { ++ brcmf_dbg(SDIO, "idle\n"); ++ sdio_claim_host(bus->sdiodev->func[1]); ++ brcmf_sdio_wd_timer(bus, 0); ++ bus->idlecount = 0; ++ brcmf_sdio_bus_sleep(bus, true, false); ++ sdio_release_host(bus->sdiodev->func[1]); ++ } ++ } else { + bus->idlecount = 0; +- brcmf_sdio_bus_sleep(bus, true, false); +- sdio_release_host(bus->sdiodev->func[1]); + } + } else { + bus->idlecount = 0; +@@ -3645,13 +3653,14 @@ static void brcmf_sdio_dataworker(struct + struct brcmf_sdio *bus = container_of(work, struct brcmf_sdio, + datawork); + +- while (atomic_read(&bus->dpc_tskcnt)) { +- atomic_set(&bus->dpc_running, 1); +- atomic_set(&bus->dpc_tskcnt, 0); ++ bus->dpc_running = true; ++ wmb(); ++ while (ACCESS_ONCE(bus->dpc_triggered)) { ++ bus->dpc_triggered = false; + brcmf_sdio_dpc(bus); + bus->idlecount = 0; +- atomic_set(&bus->dpc_running, 0); + } ++ bus->dpc_running = false; + if (brcmf_sdiod_freezing(bus->sdiodev)) { + brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DOWN); + brcmf_sdiod_try_freeze(bus->sdiodev); +@@ -4144,8 +4153,8 @@ struct brcmf_sdio *brcmf_sdio_probe(stru + bus->watchdog_tsk = NULL; + } + /* Initialize DPC thread */ +- atomic_set(&bus->dpc_tskcnt, 0); +- atomic_set(&bus->dpc_running, 0); ++ bus->dpc_triggered = false; ++ bus->dpc_running = false; + + /* Assign bus interface call back */ + bus->sdiodev->bus_if->dev = bus->sdiodev->dev; |