aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/347-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel/mac80211/patches/347-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch')
-rw-r--r--package/kernel/mac80211/patches/347-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch171
1 files changed, 171 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/347-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch b/package/kernel/mac80211/patches/347-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch
new file mode 100644
index 0000000000..c419cc68f5
--- /dev/null
+++ b/package/kernel/mac80211/patches/347-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;