1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26
27#include "rt2x00.h"
28#include "rt2x00lib.h"
29
30
31
32
33
34#define DEFAULT_RSSI -128
35
36static inline int rt2x00link_get_avg_rssi(struct ewma_rssi *ewma)
37{
38 unsigned long avg;
39
40 avg = ewma_rssi_read(ewma);
41 if (avg)
42 return -avg;
43
44 return DEFAULT_RSSI;
45}
46
47static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
48{
49 struct link_ant *ant = &rt2x00dev->link.ant;
50
51 if (rt2x00dev->link.qual.rx_success)
52 return rt2x00link_get_avg_rssi(&ant->rssi_ant);
53
54 return DEFAULT_RSSI;
55}
56
57static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev)
58{
59 struct link_ant *ant = &rt2x00dev->link.ant;
60
61 if (ant->rssi_history)
62 return ant->rssi_history;
63 return DEFAULT_RSSI;
64}
65
66static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
67 int rssi)
68{
69 struct link_ant *ant = &rt2x00dev->link.ant;
70 ant->rssi_history = rssi;
71}
72
73static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
74{
75 ewma_rssi_init(&rt2x00dev->link.ant.rssi_ant);
76}
77
78static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
79{
80 struct link_ant *ant = &rt2x00dev->link.ant;
81 struct antenna_setup new_ant;
82 int other_antenna;
83
84 int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev);
85 int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev);
86
87 memcpy(&new_ant, &ant->active, sizeof(new_ant));
88
89
90
91
92 ant->flags &= ~ANTENNA_MODE_SAMPLE;
93
94
95
96
97
98
99
100
101
102 if (sample_current >= sample_other) {
103 rt2x00link_antenna_update_rssi_history(rt2x00dev,
104 sample_current);
105 return;
106 }
107
108 other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
109
110 if (ant->flags & ANTENNA_RX_DIVERSITY)
111 new_ant.rx = other_antenna;
112
113 if (ant->flags & ANTENNA_TX_DIVERSITY)
114 new_ant.tx = other_antenna;
115
116 rt2x00lib_config_antenna(rt2x00dev, new_ant);
117}
118
119static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
120{
121 struct link_ant *ant = &rt2x00dev->link.ant;
122 struct antenna_setup new_ant;
123 int rssi_curr;
124 int rssi_old;
125
126 memcpy(&new_ant, &ant->active, sizeof(new_ant));
127
128
129
130
131
132 rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev);
133 rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev);
134 rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr);
135
136
137
138
139
140
141
142
143
144
145 if (abs(rssi_curr - rssi_old) < 5)
146 return;
147
148 ant->flags |= ANTENNA_MODE_SAMPLE;
149
150 if (ant->flags & ANTENNA_RX_DIVERSITY)
151 new_ant.rx = (new_ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
152
153 if (ant->flags & ANTENNA_TX_DIVERSITY)
154 new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
155
156 rt2x00lib_config_antenna(rt2x00dev, new_ant);
157}
158
159static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
160{
161 struct link_ant *ant = &rt2x00dev->link.ant;
162
163
164
165
166
167 if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
168 !(ant->flags & ANTENNA_TX_DIVERSITY)) {
169 ant->flags = 0;
170 return true;
171 }
172
173
174
175
176
177
178
179 if (ant->flags & ANTENNA_MODE_SAMPLE) {
180 rt2x00lib_antenna_diversity_sample(rt2x00dev);
181 return true;
182 } else if (rt2x00dev->link.count & 1) {
183 rt2x00lib_antenna_diversity_eval(rt2x00dev);
184 return true;
185 }
186
187 return false;
188}
189
190void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
191 struct sk_buff *skb,
192 struct rxdone_entry_desc *rxdesc)
193{
194 struct link *link = &rt2x00dev->link;
195 struct link_qual *qual = &rt2x00dev->link.qual;
196 struct link_ant *ant = &rt2x00dev->link.ant;
197 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
198
199
200
201
202 if (!rt2x00dev->intf_sta_count)
203 return;
204
205
206
207
208
209 qual->rx_success++;
210
211
212
213
214
215
216 if (!ieee80211_is_beacon(hdr->frame_control) ||
217 !(rxdesc->dev_flags & RXDONE_MY_BSS))
218 return;
219
220
221
222
223 ewma_rssi_add(&link->avg_rssi, -rxdesc->rssi);
224
225
226
227
228 ewma_rssi_add(&ant->rssi_ant, -rxdesc->rssi);
229}
230
231void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
232{
233 struct link *link = &rt2x00dev->link;
234
235
236
237
238
239
240
241 if (!rt2x00dev->intf_sta_count)
242 return;
243
244
245
246
247
248
249
250 if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
251 return;
252
253 rt2x00link_reset_tuner(rt2x00dev, false);
254
255 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
256 ieee80211_queue_delayed_work(rt2x00dev->hw,
257 &link->work, LINK_TUNE_INTERVAL);
258}
259
260void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
261{
262 cancel_delayed_work_sync(&rt2x00dev->link.work);
263}
264
265void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
266{
267 struct link_qual *qual = &rt2x00dev->link.qual;
268 u8 vgc_level = qual->vgc_level_reg;
269
270 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
271 return;
272
273
274
275
276
277
278
279
280
281 rt2x00dev->link.count = 0;
282 memset(qual, 0, sizeof(*qual));
283 ewma_rssi_init(&rt2x00dev->link.avg_rssi);
284
285
286
287
288
289
290 qual->vgc_level_reg = vgc_level;
291
292
293
294
295 rt2x00dev->ops->lib->reset_tuner(rt2x00dev, qual);
296
297 if (antenna)
298 rt2x00link_antenna_reset(rt2x00dev);
299}
300
301static void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev)
302{
303 struct link_qual *qual = &rt2x00dev->link.qual;
304
305 qual->rx_success = 0;
306 qual->rx_failed = 0;
307 qual->tx_success = 0;
308 qual->tx_failed = 0;
309}
310
311static void rt2x00link_tuner(struct work_struct *work)
312{
313 struct rt2x00_dev *rt2x00dev =
314 container_of(work, struct rt2x00_dev, link.work.work);
315 struct link *link = &rt2x00dev->link;
316 struct link_qual *qual = &rt2x00dev->link.qual;
317
318
319
320
321
322 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
323 test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
324 return;
325
326
327
328
329 rt2x00dev->ops->lib->link_stats(rt2x00dev, qual);
330 rt2x00dev->low_level_stats.dot11FCSErrorCount += qual->rx_failed;
331
332
333
334
335
336
337
338 if (!qual->rx_success)
339 qual->rssi = DEFAULT_RSSI;
340 else
341 qual->rssi = rt2x00link_get_avg_rssi(&link->avg_rssi);
342
343
344
345
346
347
348 if (rt2x00_has_cap_link_tuning(rt2x00dev))
349 rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
350
351
352
353
354 rt2x00leds_led_quality(rt2x00dev, qual->rssi);
355
356
357
358
359
360
361 if (rt2x00lib_antenna_diversity(rt2x00dev))
362 rt2x00link_reset_qual(rt2x00dev);
363
364
365
366
367 link->count++;
368
369 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
370 ieee80211_queue_delayed_work(rt2x00dev->hw,
371 &link->work, LINK_TUNE_INTERVAL);
372}
373
374void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
375{
376 struct link *link = &rt2x00dev->link;
377
378 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
379 rt2x00dev->ops->lib->watchdog)
380 ieee80211_queue_delayed_work(rt2x00dev->hw,
381 &link->watchdog_work,
382 WATCHDOG_INTERVAL);
383}
384
385void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
386{
387 cancel_delayed_work_sync(&rt2x00dev->link.watchdog_work);
388}
389
390static void rt2x00link_watchdog(struct work_struct *work)
391{
392 struct rt2x00_dev *rt2x00dev =
393 container_of(work, struct rt2x00_dev, link.watchdog_work.work);
394 struct link *link = &rt2x00dev->link;
395
396
397
398
399
400 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
401 return;
402
403 rt2x00dev->ops->lib->watchdog(rt2x00dev);
404
405 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
406 ieee80211_queue_delayed_work(rt2x00dev->hw,
407 &link->watchdog_work,
408 WATCHDOG_INTERVAL);
409}
410
411void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev)
412{
413 struct link *link = &rt2x00dev->link;
414
415 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
416 rt2x00dev->ops->lib->gain_calibration)
417 ieee80211_queue_delayed_work(rt2x00dev->hw,
418 &link->agc_work,
419 AGC_INTERVAL);
420}
421
422void rt2x00link_start_vcocal(struct rt2x00_dev *rt2x00dev)
423{
424 struct link *link = &rt2x00dev->link;
425
426 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
427 rt2x00dev->ops->lib->vco_calibration)
428 ieee80211_queue_delayed_work(rt2x00dev->hw,
429 &link->vco_work,
430 VCO_INTERVAL);
431}
432
433void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev)
434{
435 cancel_delayed_work_sync(&rt2x00dev->link.agc_work);
436}
437
438void rt2x00link_stop_vcocal(struct rt2x00_dev *rt2x00dev)
439{
440 cancel_delayed_work_sync(&rt2x00dev->link.vco_work);
441}
442
443static void rt2x00link_agc(struct work_struct *work)
444{
445 struct rt2x00_dev *rt2x00dev =
446 container_of(work, struct rt2x00_dev, link.agc_work.work);
447 struct link *link = &rt2x00dev->link;
448
449
450
451
452
453 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
454 return;
455
456 rt2x00dev->ops->lib->gain_calibration(rt2x00dev);
457
458 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
459 ieee80211_queue_delayed_work(rt2x00dev->hw,
460 &link->agc_work,
461 AGC_INTERVAL);
462}
463
464static void rt2x00link_vcocal(struct work_struct *work)
465{
466 struct rt2x00_dev *rt2x00dev =
467 container_of(work, struct rt2x00_dev, link.vco_work.work);
468 struct link *link = &rt2x00dev->link;
469
470
471
472
473
474 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
475 return;
476
477 rt2x00dev->ops->lib->vco_calibration(rt2x00dev);
478
479 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
480 ieee80211_queue_delayed_work(rt2x00dev->hw,
481 &link->vco_work,
482 VCO_INTERVAL);
483}
484
485void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
486{
487 INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc);
488 if (rt2x00_has_cap_vco_recalibration(rt2x00dev))
489 INIT_DELAYED_WORK(&rt2x00dev->link.vco_work, rt2x00link_vcocal);
490 INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
491 INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
492}
493