mac80211: update brcmfmac to the wireless-drivers-next-for-davem-2015-04-09
[openwrt.git] / package / kernel / mac80211 / patches / 347-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch
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 (file)
index 0000000..c419cc6
--- /dev/null
@@ -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;