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