mac80211: add minstrel performance improvements
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / ath / 551-ath9k_ubnt_uap_plus_hsr.patch
1 --- a/drivers/net/wireless/ath/ath9k/channel.c
2 +++ b/drivers/net/wireless/ath/ath9k/channel.c
3 @@ -15,6 +15,7 @@
4 */
5
6 #include "ath9k.h"
7 +#include "hsr.h"
8
9 /* Set/change channels. If the channel is really being changed, it's done
10 * by reseting the chip. To accomplish this we must first cleanup any pending
11 @@ -22,6 +23,7 @@
12 */
13 static int ath_set_channel(struct ath_softc *sc)
14 {
15 + struct device_node *np = sc->dev->of_node;
16 struct ath_hw *ah = sc->sc_ah;
17 struct ath_common *common = ath9k_hw_common(ah);
18 struct ieee80211_hw *hw = sc->hw;
19 @@ -42,6 +44,11 @@ static int ath_set_channel(struct ath_so
20 ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
21 chan->center_freq, chandef->width);
22
23 + if (of_property_read_bool(np, "ubnt,hsr")) {
24 + ath9k_hsr_enable(ah, chandef->width, chan->center_freq);
25 + ath9k_hsr_status(ah);
26 + }
27 +
28 /* update survey stats for the old channel before switching */
29 spin_lock_irqsave(&common->cc_lock, flags);
30 ath_update_survey_stats(sc);
31 --- /dev/null
32 +++ b/drivers/net/wireless/ath/ath9k/hsr.c
33 @@ -0,0 +1,247 @@
34 +/*
35 + *
36 + * The MIT License (MIT)
37 + *
38 + * Copyright (c) 2015 Kirill Berezin
39 + *
40 + * Permission is hereby granted, free of charge, to any person obtaining a copy
41 + * of this software and associated documentation files (the "Software"), to deal
42 + * in the Software without restriction, including without limitation the rights
43 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
44 + * copies of the Software, and to permit persons to whom the Software is
45 + * furnished to do so, subject to the following conditions:
46 + *
47 + * The above copyright notice and this permission notice shall be included in
48 + * all copies or substantial portions of the Software.
49 + *
50 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
51 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
52 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
53 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
54 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
55 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
56 + * SOFTWARE.
57 + *
58 + */
59 +
60 +#include <linux/io.h>
61 +#include <linux/slab.h>
62 +#include <linux/module.h>
63 +#include <linux/time.h>
64 +#include <linux/bitops.h>
65 +#include <linux/etherdevice.h>
66 +#include <linux/rtnetlink.h>
67 +#include <asm/unaligned.h>
68 +
69 +#include "hw.h"
70 +#include "ath9k.h"
71 +
72 +#define HSR_GPIO_CSN 8
73 +#define HSR_GPIO_CLK 6
74 +#define HSR_GPIO_DOUT 7
75 +#define HSR_GPIO_DIN 5
76 +
77 +/* delays are in useconds */
78 +#define HSR_DELAY_HALF_TICK 100
79 +#define HSR_DELAY_PRE_WRITE 75
80 +#define HSR_DELAY_FINAL 20000
81 +#define HSR_DELAY_TRAILING 200
82 +
83 +void ath9k_hsr_init(struct ath_hw *ah)
84 +{
85 + ath9k_hw_gpio_request_in(ah, HSR_GPIO_DIN, NULL);
86 + ath9k_hw_gpio_request_out(ah, HSR_GPIO_CSN, NULL,
87 + AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
88 + ath9k_hw_gpio_request_out(ah, HSR_GPIO_CLK, NULL,
89 + AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
90 + ath9k_hw_gpio_request_out(ah, HSR_GPIO_DOUT, NULL,
91 + AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
92 +
93 + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1);
94 + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
95 + ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, 0);
96 +
97 + udelay(HSR_DELAY_TRAILING);
98 +}
99 +
100 +static u32 ath9k_hsr_write_byte(struct ath_hw *ah, int delay, u32 value)
101 +{
102 + struct ath_common *common = ath9k_hw_common(ah);
103 + int i;
104 + u32 rval = 0;
105 +
106 + udelay(delay);
107 +
108 + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
109 + udelay(HSR_DELAY_HALF_TICK);
110 +
111 + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0);
112 + udelay(HSR_DELAY_HALF_TICK);
113 +
114 + for (i = 0; i < 8; ++i) {
115 + rval = rval << 1;
116 +
117 + /* pattern is left to right, that is 7-th bit runs first */
118 + ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1);
119 + udelay(HSR_DELAY_HALF_TICK);
120 +
121 + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1);
122 + udelay(HSR_DELAY_HALF_TICK);
123 +
124 + rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN);
125 +
126 + ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
127 + udelay(HSR_DELAY_HALF_TICK);
128 + }
129 +
130 + ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1);
131 + udelay(HSR_DELAY_HALF_TICK);
132 +
133 + ath_dbg(common, CONFIG, "ath9k_hsr_write_byte: write byte %d return value is %d %c\n",
134 + value, rval, rval > 32 ? rval : '-');
135 +
136 + return rval & 0xff;
137 +}
138 +
139 +static int ath9k_hsr_write_a_chain(struct ath_hw *ah, char *chain, int items)
140 +{
141 + int status = 0;
142 + int i = 0;
143 + int err;
144 +
145 + /* a preamble */
146 + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
147 + status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
148 +
149 + /* clear HSR's reply buffer */
150 + if (status) {
151 + int loop = 0;
152 +
153 + for (loop = 0; (loop < 42) && status; ++loop)
154 + status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE,
155 + 0);
156 +
157 + if (loop >= 42) {
158 + ATH_DBG_WARN(1,
159 + "ath9k_hsr_write_a_chain: can't clear an output buffer after a 42 cycles.\n");
160 + return -1;
161 + }
162 + }
163 +
164 + for (i = 0; (i < items) && (chain[i] != 0); ++i)
165 + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]);
166 +
167 + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
168 + mdelay(HSR_DELAY_FINAL / 1000);
169 +
170 + /* reply */
171 + memset(chain, 0, items);
172 +
173 + ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
174 + udelay(HSR_DELAY_TRAILING);
175 +
176 + for (i = 0; i < (items - 1); ++i) {
177 + u32 ret;
178 +
179 + ret = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
180 + if (ret != 0)
181 + chain[i] = (char)ret;
182 + else
183 + break;
184 +
185 + udelay(HSR_DELAY_TRAILING);
186 + }
187 +
188 + if (i <= 1)
189 + return 0;
190 +
191 + err = kstrtoint(chain + 1, 10, &i);
192 + if (err)
193 + return err;
194 +
195 + return i;
196 +}
197 +
198 +int ath9k_hsr_disable(struct ath_hw *ah)
199 +{
200 + char cmd[10] = {'b', '4', '0', 0, 0, 0, 0, 0, 0, 0};
201 + int ret;
202 +
203 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
204 + if ((ret > 0) && (*cmd == 'B'))
205 + return 0;
206 +
207 + return -1;
208 +}
209 +
210 +int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq)
211 +{
212 + char cmd[10];
213 + int ret;
214 +
215 + /* Bandwidth argument is 0 sometimes. Assume default 802.11bgn
216 + * 20MHz on invalid values
217 + */
218 + if ((bw != 5) && (bw != 10) && (bw != 20) && (bw != 40))
219 + bw = 20;
220 +
221 + memset(cmd, 0, sizeof(cmd));
222 + *cmd = 'b';
223 + snprintf(cmd + 1, 3, "%02d", bw);
224 +
225 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
226 + if ((*cmd != 'B') || (ret != bw)) {
227 + ATH_DBG_WARN(1,
228 + "ath9k_hsr_enable: failed changing bandwidth -> set (%d,%d) reply (%d, %d)\n",
229 + 'b', bw, *cmd, ret);
230 + return -1;
231 + }
232 +
233 + memset(cmd, 0, sizeof(cmd));
234 + *cmd = 'x';
235 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
236 + if (*cmd != 'X') {
237 + ATH_DBG_WARN(1,
238 + "ath9k_hsr_enable: failed 'x' command -> reply (%d, %d)\n",
239 + *cmd, ret);
240 + return -1;
241 + }
242 +
243 + memset(cmd, 0, sizeof(cmd));
244 + *cmd = 'm';
245 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
246 + if (*cmd != 'M') {
247 + ATH_DBG_WARN(1,
248 + "ath9k_hsr_enable: failed 'm' command -> reply (%d, %d)\n",
249 + *cmd, ret);
250 + return -1;
251 + }
252 +
253 + memset(cmd, 0, sizeof(cmd));
254 + *cmd = 'f';
255 + snprintf(cmd + 1, 6, "%05d", fq);
256 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
257 + if ((*cmd != 'F') && (ret != fq)) {
258 + ATH_DBG_WARN(1,
259 + "ath9k_hsr_enable: failed set frequency -> reply (%d, %d)\n",
260 + *cmd, ret);
261 + return -1;
262 + }
263 +
264 + return 0;
265 +}
266 +
267 +int ath9k_hsr_status(struct ath_hw *ah)
268 +{
269 + char cmd[10] = {'s', 0, 0, 0, 0, 0, 0, 0, 0, 0};
270 + int ret;
271 +
272 + ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd));
273 + if (*cmd != 'S') {
274 + ATH_DBG_WARN(1, "ath9k_hsr_status: returned %d,%d\n", *cmd,
275 + ret);
276 + return -1;
277 + }
278 +
279 + return 0;
280 +}
281 --- /dev/null
282 +++ b/drivers/net/wireless/ath/ath9k/hsr.h
283 @@ -0,0 +1,48 @@
284 +/*
285 + * The MIT License (MIT)
286 + *
287 + * Copyright (c) 2015 Kirill Berezin
288 + *
289 + * Permission is hereby granted, free of charge, to any person obtaining a copy
290 + * of this software and associated documentation files (the "Software"), to deal
291 + * in the Software without restriction, including without limitation the rights
292 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
293 + * copies of the Software, and to permit persons to whom the Software is
294 + * furnished to do so, subject to the following conditions:
295 + *
296 + * The above copyright notice and this permission notice shall be included in
297 + * all copies or substantial portions of the Software.
298 + *
299 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
300 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
301 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
302 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
303 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
304 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
305 + * SOFTWARE.
306 + */
307 +
308 +#ifndef HSR_H
309 +#define HSR_H
310 +
311 +#ifdef CPTCFG_ATH9K_UBNTHSR
312 +
313 +void ath9k_hsr_init(struct ath_hw *ah);
314 +int ath9k_hsr_disable(struct ath_hw *ah);
315 +int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq);
316 +int ath9k_hsr_status(struct ath_hw *ah);
317 +
318 +#else
319 +static inline void ath9k_hsr_init(struct ath_hw *ah) {}
320 +
321 +static inline int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq)
322 +{
323 + return 0;
324 +}
325 +
326 +static inline int ath9k_hsr_disable(struct ath_hw *ah) { return 0; }
327 +static inline int ath9k_hsr_status(struct ath_hw *ah) { return 0; }
328 +
329 +#endif
330 +
331 +#endif /* HSR_H */
332 --- a/drivers/net/wireless/ath/ath9k/main.c
333 +++ b/drivers/net/wireless/ath/ath9k/main.c
334 @@ -18,6 +18,7 @@
335 #include <linux/delay.h>
336 #include "ath9k.h"
337 #include "btcoex.h"
338 +#include "hsr.h"
339
340 static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
341 u32 queues, bool drop);
342 @@ -652,6 +653,7 @@ void ath_reset_work(struct work_struct *
343 static int ath9k_start(struct ieee80211_hw *hw)
344 {
345 struct ath_softc *sc = hw->priv;
346 + struct device_node *np = sc->dev->of_node;
347 struct ath_hw *ah = sc->sc_ah;
348 struct ath_common *common = ath9k_hw_common(ah);
349 struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan;
350 @@ -730,6 +732,11 @@ static int ath9k_start(struct ieee80211_
351 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
352 }
353
354 + if (of_property_read_bool(np, "ubnt,hsr")) {
355 + ath9k_hsr_init(ah);
356 + ath9k_hsr_disable(ah);
357 + }
358 +
359 /*
360 * Reset key cache to sane defaults (all entries cleared) instead of
361 * semi-random values after suspend/resume.
362 --- a/drivers/net/wireless/ath/ath9k/Makefile
363 +++ b/drivers/net/wireless/ath/ath9k/Makefile
364 @@ -17,6 +17,7 @@ ath9k-$(CPTCFG_ATH9K_DFS_CERTIFIED) += d
365 ath9k-$(CPTCFG_ATH9K_TX99) += tx99.o
366 ath9k-$(CPTCFG_ATH9K_WOW) += wow.o
367 ath9k-$(CPTCFG_ATH9K_HWRNG) += rng.o
368 +ath9k-$(CPTCFG_ATH9K_UBNTHSR) += hsr.o
369
370 ath9k-$(CPTCFG_ATH9K_DEBUGFS) += debug.o
371
372 --- a/local-symbols
373 +++ b/local-symbols
374 @@ -112,6 +112,7 @@ ATH9K_WOW=
375 ATH9K_RFKILL=
376 ATH9K_CHANNEL_CONTEXT=
377 ATH9K_PCOEM=
378 +ATH9K_UBNTHSR=
379 ATH9K_PCI_NO_EEPROM=
380 ATH9K_HTC=
381 ATH9K_HTC_DEBUGFS=
382 --- a/drivers/net/wireless/ath/ath9k/Kconfig
383 +++ b/drivers/net/wireless/ath/ath9k/Kconfig
384 @@ -60,6 +60,19 @@ config ATH9K_AHB
385 Say Y, if you have a SoC with a compatible built-in
386 wireless MAC. Say N if unsure.
387
388 +config ATH9K_UBNTHSR
389 + bool "Ubiquiti UniFi Outdoor Plus HSR support"
390 + depends on ATH9K
391 + ---help---
392 + This options enables code to control the HSR RF
393 + filter in the receive path of the Ubiquiti UniFi
394 + Outdoor Plus access point.
395 +
396 + Say Y if you want to use the access point. The
397 + code will only be used if the device is detected,
398 + so it does not harm other setup other than occupying
399 + a bit of memory.
400 +
401 config ATH9K_DEBUGFS
402 bool "Atheros ath9k debugging"
403 depends on ATH9K && DEBUG_FS