mac80211: try to workaround some brcmfmac bug with handling interfaces
[15.05/openwrt.git] / package / kernel / mac80211 / patches / 347-brcmfmac-Add-necessary-memory-barriers-for-SDIO.patch
1 From: Hante Meuleman <meuleman@broadcom.com>
2 Date: Wed, 18 Mar 2015 13:25:22 +0100
3 Subject: [PATCH] brcmfmac: Add necessary memory barriers for SDIO.
4
5 SDIO uses a thread to handle all communication with the device,
6 for this data is exchanged between threads. This data needs proper
7 memory barriers to make sure that data "exchange" is going correct.
8
9 Reviewed-by: Arend Van Spriel <arend@broadcom.com>
10 Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
11 Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
12 Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
13 Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
14 Signed-off-by: Arend van Spriel <arend@broadcom.com>
15 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
16 ---
17
18 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
19 +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
20 @@ -507,8 +507,8 @@ struct brcmf_sdio {
21  
22         struct workqueue_struct *brcmf_wq;
23         struct work_struct datawork;
24 -       atomic_t dpc_tskcnt;
25 -       atomic_t dpc_running;
26 +       bool dpc_triggered;
27 +       bool dpc_running;
28  
29         bool txoff;             /* Transmit flow-controlled */
30         struct brcmf_sdio_count sdcnt;
31 @@ -2713,6 +2713,7 @@ static void brcmf_sdio_dpc(struct brcmf_
32                         err = brcmf_sdio_tx_ctrlframe(bus,  bus->ctrl_frame_buf,
33                                                       bus->ctrl_frame_len);
34                         bus->ctrl_frame_err = err;
35 +                       wmb();
36                         bus->ctrl_frame_stat = false;
37                 }
38                 sdio_release_host(bus->sdiodev->func[1]);
39 @@ -2734,6 +2735,7 @@ static void brcmf_sdio_dpc(struct brcmf_
40                         sdio_claim_host(bus->sdiodev->func[1]);
41                         if (bus->ctrl_frame_stat) {
42                                 bus->ctrl_frame_err = -ENODEV;
43 +                               wmb();
44                                 bus->ctrl_frame_stat = false;
45                                 brcmf_sdio_wait_event_wakeup(bus);
46                         }
47 @@ -2744,7 +2746,7 @@ static void brcmf_sdio_dpc(struct brcmf_
48                    (!atomic_read(&bus->fcstate) &&
49                     brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
50                     data_ok(bus))) {
51 -               atomic_inc(&bus->dpc_tskcnt);
52 +               bus->dpc_triggered = true;
53         }
54  }
55  
56 @@ -2940,6 +2942,7 @@ brcmf_sdio_bus_txctl(struct device *dev,
57         /* Send from dpc */
58         bus->ctrl_frame_buf = msg;
59         bus->ctrl_frame_len = msglen;
60 +       wmb();
61         bus->ctrl_frame_stat = true;
62  
63         brcmf_sdio_trigger_dpc(bus);
64 @@ -2958,6 +2961,7 @@ brcmf_sdio_bus_txctl(struct device *dev,
65         if (!ret) {
66                 brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n",
67                           bus->ctrl_frame_err);
68 +               rmb();
69                 ret = bus->ctrl_frame_err;
70         }
71  
72 @@ -3526,8 +3530,8 @@ done:
73  
74  void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus)
75  {
76 -       if (atomic_read(&bus->dpc_tskcnt) == 0) {
77 -               atomic_inc(&bus->dpc_tskcnt);
78 +       if (!bus->dpc_triggered) {
79 +               bus->dpc_triggered = true;
80                 queue_work(bus->brcmf_wq, &bus->datawork);
81         }
82  }
83 @@ -3558,7 +3562,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *b
84         if (!bus->intr)
85                 brcmf_err("isr w/o interrupt configured!\n");
86  
87 -       atomic_inc(&bus->dpc_tskcnt);
88 +       bus->dpc_triggered = true;
89         queue_work(bus->brcmf_wq, &bus->datawork);
90  }
91  
92 @@ -3578,7 +3582,7 @@ static void brcmf_sdio_bus_watchdog(stru
93                 if (!bus->intr ||
94                     (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) {
95  
96 -                       if (atomic_read(&bus->dpc_tskcnt) == 0) {
97 +                       if (!bus->dpc_triggered) {
98                                 u8 devpend;
99  
100                                 sdio_claim_host(bus->sdiodev->func[1]);
101 @@ -3596,7 +3600,7 @@ static void brcmf_sdio_bus_watchdog(stru
102                                 bus->sdcnt.pollcnt++;
103                                 atomic_set(&bus->ipend, 1);
104  
105 -                               atomic_inc(&bus->dpc_tskcnt);
106 +                               bus->dpc_triggered = true;
107                                 queue_work(bus->brcmf_wq, &bus->datawork);
108                         }
109                 }
110 @@ -3623,17 +3627,21 @@ static void brcmf_sdio_bus_watchdog(stru
111  #endif                         /* DEBUG */
112  
113         /* On idle timeout clear activity flag and/or turn off clock */
114 -       if ((atomic_read(&bus->dpc_tskcnt) == 0) &&
115 -           (atomic_read(&bus->dpc_running) == 0) &&
116 -           (bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
117 -               bus->idlecount++;
118 -               if (bus->idlecount > bus->idletime) {
119 -                       brcmf_dbg(SDIO, "idle\n");
120 -                       sdio_claim_host(bus->sdiodev->func[1]);
121 -                       brcmf_sdio_wd_timer(bus, 0);
122 +       if (!bus->dpc_triggered) {
123 +               rmb();
124 +               if ((!bus->dpc_running) && (bus->idletime > 0) &&
125 +                   (bus->clkstate == CLK_AVAIL)) {
126 +                       bus->idlecount++;
127 +                       if (bus->idlecount > bus->idletime) {
128 +                               brcmf_dbg(SDIO, "idle\n");
129 +                               sdio_claim_host(bus->sdiodev->func[1]);
130 +                               brcmf_sdio_wd_timer(bus, 0);
131 +                               bus->idlecount = 0;
132 +                               brcmf_sdio_bus_sleep(bus, true, false);
133 +                               sdio_release_host(bus->sdiodev->func[1]);
134 +                       }
135 +               } else {
136                         bus->idlecount = 0;
137 -                       brcmf_sdio_bus_sleep(bus, true, false);
138 -                       sdio_release_host(bus->sdiodev->func[1]);
139                 }
140         } else {
141                 bus->idlecount = 0;
142 @@ -3645,13 +3653,14 @@ static void brcmf_sdio_dataworker(struct
143         struct brcmf_sdio *bus = container_of(work, struct brcmf_sdio,
144                                               datawork);
145  
146 -       while (atomic_read(&bus->dpc_tskcnt)) {
147 -               atomic_set(&bus->dpc_running, 1);
148 -               atomic_set(&bus->dpc_tskcnt, 0);
149 +       bus->dpc_running = true;
150 +       wmb();
151 +       while (ACCESS_ONCE(bus->dpc_triggered)) {
152 +               bus->dpc_triggered = false;
153                 brcmf_sdio_dpc(bus);
154                 bus->idlecount = 0;
155 -               atomic_set(&bus->dpc_running, 0);
156         }
157 +       bus->dpc_running = false;
158         if (brcmf_sdiod_freezing(bus->sdiodev)) {
159                 brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DOWN);
160                 brcmf_sdiod_try_freeze(bus->sdiodev);
161 @@ -4144,8 +4153,8 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
162                 bus->watchdog_tsk = NULL;
163         }
164         /* Initialize DPC thread */
165 -       atomic_set(&bus->dpc_tskcnt, 0);
166 -       atomic_set(&bus->dpc_running, 0);
167 +       bus->dpc_triggered = false;
168 +       bus->dpc_running = false;
169  
170         /* Assign bus interface call back */
171         bus->sdiodev->bus_if->dev = bus->sdiodev->dev;