aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c27
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c50
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c5
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h99
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c145
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c49
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c57
7 files changed, 233 insertions, 199 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index e87ad43e8e8d..9104113270d0 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -600,36 +600,37 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev,
600 qual->false_cca = bbp; 600 qual->false_cca = bbp;
601} 601}
602 602
603static inline void rt2400pci_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level) 603static inline void rt2400pci_set_vgc(struct rt2x00_dev *rt2x00dev,
604 struct link_qual *qual, u8 vgc_level)
604{ 605{
605 rt2400pci_bbp_write(rt2x00dev, 13, vgc_level); 606 rt2400pci_bbp_write(rt2x00dev, 13, vgc_level);
606 rt2x00dev->link.vgc_level = vgc_level; 607 qual->vgc_level = vgc_level;
607 rt2x00dev->link.vgc_level_reg = vgc_level; 608 qual->vgc_level_reg = vgc_level;
608} 609}
609 610
610static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev) 611static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
612 struct link_qual *qual)
611{ 613{
612 rt2400pci_set_vgc(rt2x00dev, 0x08); 614 rt2400pci_set_vgc(rt2x00dev, qual, 0x08);
613} 615}
614 616
615static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) 617static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev,
618 struct link_qual *qual, const u32 count)
616{ 619{
617 struct link *link = &rt2x00dev->link;
618
619 /* 620 /*
620 * The link tuner should not run longer then 60 seconds, 621 * The link tuner should not run longer then 60 seconds,
621 * and should run once every 2 seconds. 622 * and should run once every 2 seconds.
622 */ 623 */
623 if (link->count > 60 || !(link->count & 1)) 624 if (count > 60 || !(count & 1))
624 return; 625 return;
625 626
626 /* 627 /*
627 * Base r13 link tuning on the false cca count. 628 * Base r13 link tuning on the false cca count.
628 */ 629 */
629 if ((link->qual.false_cca > 512) && (link->vgc_level < 0x20)) 630 if ((qual->false_cca > 512) && (qual->vgc_level < 0x20))
630 rt2400pci_set_vgc(rt2x00dev, ++link->vgc_level); 631 rt2400pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level);
631 else if ((link->qual.false_cca < 100) && (link->vgc_level > 0x08)) 632 else if ((qual->false_cca < 100) && (qual->vgc_level > 0x08))
632 rt2400pci_set_vgc(rt2x00dev, --link->vgc_level); 633 rt2400pci_set_vgc(rt2x00dev, qual, --qual->vgc_level);
633} 634}
634 635
635/* 636/*
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 5b98a74a2554..fb86e2c55248 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -639,31 +639,31 @@ static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev,
639 qual->false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA); 639 qual->false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA);
640} 640}
641 641
642static inline void rt2500pci_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level) 642static inline void rt2500pci_set_vgc(struct rt2x00_dev *rt2x00dev,
643 struct link_qual *qual, u8 vgc_level)
643{ 644{
644 if (rt2x00dev->link.vgc_level_reg != vgc_level) { 645 if (qual->vgc_level_reg != vgc_level) {
645 rt2500pci_bbp_write(rt2x00dev, 17, vgc_level); 646 rt2500pci_bbp_write(rt2x00dev, 17, vgc_level);
646 rt2x00dev->link.vgc_level_reg = vgc_level; 647 qual->vgc_level_reg = vgc_level;
647 } 648 }
648} 649}
649 650
650static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev) 651static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
652 struct link_qual *qual)
651{ 653{
652 rt2500pci_set_vgc(rt2x00dev, 0x48); 654 rt2500pci_set_vgc(rt2x00dev, qual, 0x48);
653} 655}
654 656
655static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev) 657static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev,
658 struct link_qual *qual, const u32 count)
656{ 659{
657 struct link *link = &rt2x00dev->link;
658 int rssi = rt2x00_get_link_rssi(link);
659
660 /* 660 /*
661 * To prevent collisions with MAC ASIC on chipsets 661 * To prevent collisions with MAC ASIC on chipsets
662 * up to version C the link tuning should halt after 20 662 * up to version C the link tuning should halt after 20
663 * seconds while being associated. 663 * seconds while being associated.
664 */ 664 */
665 if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D && 665 if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
666 rt2x00dev->intf_associated && link->count > 20) 666 rt2x00dev->intf_associated && count > 20)
667 return; 667 return;
668 668
669 /* 669 /*
@@ -681,25 +681,25 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
681 * then corrupt the R17 tuning. To remidy this the tuning should 681 * then corrupt the R17 tuning. To remidy this the tuning should
682 * be stopped (While making sure the R17 value will not exceed limits) 682 * be stopped (While making sure the R17 value will not exceed limits)
683 */ 683 */
684 if (rssi < -80 && link->count > 20) { 684 if (qual->rssi < -80 && count > 20) {
685 if (link->vgc_level_reg >= 0x41) 685 if (qual->vgc_level_reg >= 0x41)
686 rt2500pci_set_vgc(rt2x00dev, link->vgc_level); 686 rt2500pci_set_vgc(rt2x00dev, qual, qual->vgc_level);
687 return; 687 return;
688 } 688 }
689 689
690 /* 690 /*
691 * Special big-R17 for short distance 691 * Special big-R17 for short distance
692 */ 692 */
693 if (rssi >= -58) { 693 if (qual->rssi >= -58) {
694 rt2500pci_set_vgc(rt2x00dev, 0x50); 694 rt2500pci_set_vgc(rt2x00dev, qual, 0x50);
695 return; 695 return;
696 } 696 }
697 697
698 /* 698 /*
699 * Special mid-R17 for middle distance 699 * Special mid-R17 for middle distance
700 */ 700 */
701 if (rssi >= -74) { 701 if (qual->rssi >= -74) {
702 rt2500pci_set_vgc(rt2x00dev, 0x41); 702 rt2500pci_set_vgc(rt2x00dev, qual, 0x41);
703 return; 703 return;
704 } 704 }
705 705
@@ -707,8 +707,8 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
707 * Leave short or middle distance condition, restore r17 707 * Leave short or middle distance condition, restore r17
708 * to the dynamic tuning range. 708 * to the dynamic tuning range.
709 */ 709 */
710 if (link->vgc_level_reg >= 0x41) { 710 if (qual->vgc_level_reg >= 0x41) {
711 rt2500pci_set_vgc(rt2x00dev, link->vgc_level); 711 rt2500pci_set_vgc(rt2x00dev, qual, qual->vgc_level);
712 return; 712 return;
713 } 713 }
714 714
@@ -718,12 +718,12 @@ dynamic_cca_tune:
718 * R17 is inside the dynamic tuning range, 718 * R17 is inside the dynamic tuning range,
719 * start tuning the link based on the false cca counter. 719 * start tuning the link based on the false cca counter.
720 */ 720 */
721 if (link->qual.false_cca > 512 && link->vgc_level_reg < 0x40) { 721 if (qual->false_cca > 512 && qual->vgc_level_reg < 0x40) {
722 rt2500pci_set_vgc(rt2x00dev, ++link->vgc_level_reg); 722 rt2500pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level_reg);
723 link->vgc_level = link->vgc_level_reg; 723 qual->vgc_level = qual->vgc_level_reg;
724 } else if (link->qual.false_cca < 100 && link->vgc_level_reg > 0x32) { 724 } else if (qual->false_cca < 100 && qual->vgc_level_reg > 0x32) {
725 rt2500pci_set_vgc(rt2x00dev, --link->vgc_level_reg); 725 rt2500pci_set_vgc(rt2x00dev, qual, --qual->vgc_level_reg);
726 link->vgc_level = link->vgc_level_reg; 726 qual->vgc_level = qual->vgc_level_reg;
727 } 727 }
728} 728}
729 729
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 23cf585f03a4..557fcf2b30e4 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -698,7 +698,8 @@ static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev,
698 qual->false_cca = rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR); 698 qual->false_cca = rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR);
699} 699}
700 700
701static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev) 701static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev,
702 struct link_qual *qual)
702{ 703{
703 u16 eeprom; 704 u16 eeprom;
704 u16 value; 705 u16 value;
@@ -719,7 +720,7 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
719 value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_VGCUPPER); 720 value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_VGCUPPER);
720 rt2500usb_bbp_write(rt2x00dev, 17, value); 721 rt2500usb_bbp_write(rt2x00dev, 17, value);
721 722
722 rt2x00dev->link.vgc_level = value; 723 qual->vgc_level = value;
723} 724}
724 725
725/* 726/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 8935f2c005ce..dea502234cf8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -177,52 +177,41 @@ struct antenna_setup {
177 */ 177 */
178struct link_qual { 178struct link_qual {
179 /* 179 /*
180 * Statistics required for Link tuning. 180 * Statistics required for Link tuning by driver
181 * For the average RSSI value we use the "Walking average" approach. 181 * The rssi value is provided by rt2x00lib during the
182 * When adding RSSI to the average value the following calculation 182 * link_tuner() callback function.
183 * is needed: 183 * The false_cca field is filled during the link_stats()
184 * 184 * callback function and could be used during the
185 * avg_rssi = ((avg_rssi * 7) + rssi) / 8; 185 * link_tuner() callback function.
186 */
187 int rssi;
188 int false_cca;
189
190 /*
191 * VGC levels
192 * Hardware driver will tune the VGC level during each call
193 * to the link_tuner() callback function. This vgc_level is
194 * is determined based on the link quality statistics like
195 * average RSSI and the false CCA count.
186 * 196 *
187 * The advantage of this approach is that we only need 1 variable 197 * In some cases the drivers need to differentiate between
188 * to store the average in (No need for a count and a total). 198 * the currently "desired" VGC level and the level configured
189 * But more importantly, normal average values will over time 199 * in the hardware. The latter is important to reduce the
190 * move less and less towards newly added values this results 200 * number of BBP register reads to reduce register access
191 * that with link tuning, the device can have a very good RSSI 201 * overhead. For this reason we store both values here.
192 * for a few minutes but when the device is moved away from the AP
193 * the average will not decrease fast enough to compensate.
194 * The walking average compensates this and will move towards
195 * the new values correctly allowing a effective link tuning.
196 */ 202 */
197 int avg_rssi; 203 u8 vgc_level;
198 int false_cca; 204 u8 vgc_level_reg;
199 205
200 /* 206 /*
201 * Statistics required for Signal quality calculation. 207 * Statistics required for Signal quality calculation.
202 * For calculating the Signal quality we have to determine 208 * These fields might be changed during the link_stats()
203 * the total number of success and failed RX and TX frames. 209 * callback function.
204 * After that we also use the average RSSI value to help
205 * determining the signal quality.
206 * For the calculation we will use the following algorithm:
207 *
208 * rssi_percentage = (avg_rssi * 100) / rssi_offset
209 * rx_percentage = (rx_success * 100) / rx_total
210 * tx_percentage = (tx_success * 100) / tx_total
211 * avg_signal = ((WEIGHT_RSSI * avg_rssi) +
212 * (WEIGHT_TX * tx_percentage) +
213 * (WEIGHT_RX * rx_percentage)) / 100
214 *
215 * This value should then be checked to not be greater then 100.
216 */ 210 */
217 int rx_percentage;
218 int rx_success; 211 int rx_success;
219 int rx_failed; 212 int rx_failed;
220 int tx_percentage;
221 int tx_success; 213 int tx_success;
222 int tx_failed; 214 int tx_failed;
223#define WEIGHT_RSSI 20
224#define WEIGHT_RX 40
225#define WEIGHT_TX 40
226}; 215};
227 216
228/* 217/*
@@ -286,14 +275,16 @@ struct link {
286 struct link_ant ant; 275 struct link_ant ant;
287 276
288 /* 277 /*
289 * Active VGC level (for false cca tuning) 278 * Currently active average RSSI value
290 */ 279 */
291 u8 vgc_level; 280 int avg_rssi;
292 281
293 /* 282 /*
294 * VGC level as configured in register 283 * Currently precalculated percentages of successful
284 * TX and RX frames.
295 */ 285 */
296 u8 vgc_level_reg; 286 int rx_percentage;
287 int tx_percentage;
297 288
298 /* 289 /*
299 * Work structure for scheduling periodic link tuning. 290 * Work structure for scheduling periodic link tuning.
@@ -302,28 +293,6 @@ struct link {
302}; 293};
303 294
304/* 295/*
305 * Small helper macro to work with moving/walking averages.
306 */
307#define MOVING_AVERAGE(__avg, __val, __samples) \
308 ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) )
309
310/*
311 * When we lack RSSI information return something less then -80 to
312 * tell the driver to tune the device to maximum sensitivity.
313 */
314#define DEFAULT_RSSI ( -128 )
315
316/*
317 * Link quality access functions.
318 */
319static inline int rt2x00_get_link_rssi(struct link *link)
320{
321 if (link->qual.avg_rssi && link->qual.rx_success)
322 return link->qual.avg_rssi;
323 return DEFAULT_RSSI;
324}
325
326/*
327 * Interface structure 296 * Interface structure
328 * Per interface configuration details, this structure 297 * Per interface configuration details, this structure
329 * is allocated as the private data for ieee80211_vif. 298 * is allocated as the private data for ieee80211_vif.
@@ -522,8 +491,10 @@ struct rt2x00lib_ops {
522 int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev); 491 int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev);
523 void (*link_stats) (struct rt2x00_dev *rt2x00dev, 492 void (*link_stats) (struct rt2x00_dev *rt2x00dev,
524 struct link_qual *qual); 493 struct link_qual *qual);
525 void (*reset_tuner) (struct rt2x00_dev *rt2x00dev); 494 void (*reset_tuner) (struct rt2x00_dev *rt2x00dev,
526 void (*link_tuner) (struct rt2x00_dev *rt2x00dev); 495 struct link_qual *qual);
496 void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
497 struct link_qual *qual, const u32 count);
527 498
528 /* 499 /*
529 * TX control handlers 500 * TX control handlers
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index 0462d5ab6e97..ee08f1167f59 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -29,6 +29,71 @@
29#include "rt2x00.h" 29#include "rt2x00.h"
30#include "rt2x00lib.h" 30#include "rt2x00lib.h"
31 31
32/*
33 * When we lack RSSI information return something less then -80 to
34 * tell the driver to tune the device to maximum sensitivity.
35 */
36#define DEFAULT_RSSI -128
37
38/*
39 * When no TX/RX percentage could be calculated due to lack of
40 * frames on the air, we fallback to a percentage of 50%.
41 * This will assure we will get at least get some decent value
42 * when the link tuner starts.
43 * The value will be dropped and overwritten with the correct (measured)
44 * value anyway during the first run of the link tuner.
45 */
46#define DEFAULT_PERCENTAGE 50
47
48/*
49 * Small helper macro to work with moving/walking averages.
50 * When adding a value to the average value the following calculation
51 * is needed:
52 *
53 * avg_rssi = ((avg_rssi * 7) + rssi) / 8;
54 *
55 * The advantage of this approach is that we only need 1 variable
56 * to store the average in (No need for a count and a total).
57 * But more importantly, normal average values will over time
58 * move less and less towards newly added values this results
59 * that with link tuning, the device can have a very good RSSI
60 * for a few minutes but when the device is moved away from the AP
61 * the average will not decrease fast enough to compensate.
62 * The walking average compensates this and will move towards
63 * the new values correctly allowing a effective link tuning.
64 */
65#define MOVING_AVERAGE(__avg, __val, __samples) \
66 ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) )
67
68/*
69 * Small helper macro for percentage calculation
70 * This is a very simple macro with the only catch that it will
71 * produce a default value in case no total value was provided.
72 */
73#define PERCENTAGE(__value, __total) \
74 ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) )
75
76/*
77 * For calculating the Signal quality we have determined
78 * the total number of success and failed RX and TX frames.
79 * With the addition of the average RSSI value we can determine
80 * the link quality using the following algorithm:
81 *
82 * rssi_percentage = (avg_rssi * 100) / rssi_offset
83 * rx_percentage = (rx_success * 100) / rx_total
84 * tx_percentage = (tx_success * 100) / tx_total
85 * avg_signal = ((WEIGHT_RSSI * avg_rssi) +
86 * (WEIGHT_TX * tx_percentage) +
87 * (WEIGHT_RX * rx_percentage)) / 100
88 *
89 * This value should then be checked to not be greater then 100.
90 * This means the values of WEIGHT_RSSI, WEIGHT_RX, WEIGHT_TX must
91 * sum up to 100 as well.
92 */
93#define WEIGHT_RSSI 20
94#define WEIGHT_RX 40
95#define WEIGHT_TX 40
96
32static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) 97static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
33{ 98{
34 struct link_ant *ant = &rt2x00dev->link.ant; 99 struct link_ant *ant = &rt2x00dev->link.ant;
@@ -191,6 +256,7 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
191 struct sk_buff *skb, 256 struct sk_buff *skb,
192 struct rxdone_entry_desc *rxdesc) 257 struct rxdone_entry_desc *rxdesc)
193{ 258{
259 struct link *link = &rt2x00dev->link;
194 struct link_qual *qual = &rt2x00dev->link.qual; 260 struct link_qual *qual = &rt2x00dev->link.qual;
195 struct link_ant *ant = &rt2x00dev->link.ant; 261 struct link_ant *ant = &rt2x00dev->link.ant;
196 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 262 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
@@ -215,9 +281,9 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
215 /* 281 /*
216 * Update global RSSI 282 * Update global RSSI
217 */ 283 */
218 if (qual->avg_rssi) 284 if (link->avg_rssi)
219 avg_rssi = MOVING_AVERAGE(qual->avg_rssi, rxdesc->rssi, 8); 285 avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi, 8);
220 qual->avg_rssi = avg_rssi; 286 link->avg_rssi = avg_rssi;
221 287
222 /* 288 /*
223 * Update antenna RSSI 289 * Update antenna RSSI
@@ -229,21 +295,13 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
229 295
230static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev) 296static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
231{ 297{
298 struct link *link = &rt2x00dev->link;
232 struct link_qual *qual = &rt2x00dev->link.qual; 299 struct link_qual *qual = &rt2x00dev->link.qual;
233 300
234 if (qual->rx_failed || qual->rx_success) 301 link->rx_percentage =
235 qual->rx_percentage = 302 PERCENTAGE(qual->rx_success, qual->rx_failed + qual->rx_success);
236 (qual->rx_success * 100) / 303 link->tx_percentage =
237 (qual->rx_failed + qual->rx_success); 304 PERCENTAGE(qual->tx_success, qual->tx_failed + qual->tx_success);
238 else
239 qual->rx_percentage = 50;
240
241 if (qual->tx_failed || qual->tx_success)
242 qual->tx_percentage =
243 (qual->tx_success * 100) /
244 (qual->tx_failed + qual->tx_success);
245 else
246 qual->tx_percentage = 50;
247 305
248 qual->rx_success = 0; 306 qual->rx_success = 0;
249 qual->rx_failed = 0; 307 qual->rx_failed = 0;
@@ -253,7 +311,7 @@ static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
253 311
254int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi) 312int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi)
255{ 313{
256 struct link_qual *qual = &rt2x00dev->link.qual; 314 struct link *link = &rt2x00dev->link;
257 int rssi_percentage = 0; 315 int rssi_percentage = 0;
258 int signal; 316 int signal;
259 317
@@ -267,22 +325,22 @@ int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi)
267 * Calculate the different percentages, 325 * Calculate the different percentages,
268 * which will be used for the signal. 326 * which will be used for the signal.
269 */ 327 */
270 rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset; 328 rssi_percentage = PERCENTAGE(rssi, rt2x00dev->rssi_offset);
271 329
272 /* 330 /*
273 * Add the individual percentages and use the WEIGHT 331 * Add the individual percentages and use the WEIGHT
274 * defines to calculate the current link signal. 332 * defines to calculate the current link signal.
275 */ 333 */
276 signal = ((WEIGHT_RSSI * rssi_percentage) + 334 signal = ((WEIGHT_RSSI * rssi_percentage) +
277 (WEIGHT_TX * qual->tx_percentage) + 335 (WEIGHT_TX * link->tx_percentage) +
278 (WEIGHT_RX * qual->rx_percentage)) / 100; 336 (WEIGHT_RX * link->rx_percentage)) / 100;
279 337
280 return max_t(int, signal, 100); 338 return max_t(int, signal, 100);
281} 339}
282 340
283void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) 341void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
284{ 342{
285 struct link_qual *qual = &rt2x00dev->link.qual; 343 struct link *link = &rt2x00dev->link;
286 344
287 /* 345 /*
288 * Link tuning should only be performed when 346 * Link tuning should only be performed when
@@ -293,26 +351,13 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
293 if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count) 351 if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
294 return; 352 return;
295 353
296 /* 354 link->rx_percentage = DEFAULT_PERCENTAGE;
297 * Clear all (possibly) pre-existing quality statistics. 355 link->tx_percentage = DEFAULT_PERCENTAGE;
298 */
299 memset(qual, 0, sizeof(*qual));
300
301 /*
302 * The RX and TX percentage should start at 50%
303 * this will assure we will get at least get some
304 * decent value when the link tuner starts.
305 * The value will be dropped and overwritten with
306 * the correct (measured) value anyway during the
307 * first run of the link tuner.
308 */
309 qual->rx_percentage = 50;
310 qual->tx_percentage = 50;
311 356
312 rt2x00link_reset_tuner(rt2x00dev, false); 357 rt2x00link_reset_tuner(rt2x00dev, false);
313 358
314 queue_delayed_work(rt2x00dev->hw->workqueue, 359 queue_delayed_work(rt2x00dev->hw->workqueue,
315 &rt2x00dev->link.work, LINK_TUNE_INTERVAL); 360 &link->work, LINK_TUNE_INTERVAL);
316} 361}
317 362
318void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev) 363void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
@@ -322,6 +367,8 @@ void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
322 367
323void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna) 368void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
324{ 369{
370 struct link_qual *qual = &rt2x00dev->link.qual;
371
325 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 372 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
326 return; 373 return;
327 374
@@ -334,12 +381,12 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
334 * first minute after being enabled. 381 * first minute after being enabled.
335 */ 382 */
336 rt2x00dev->link.count = 0; 383 rt2x00dev->link.count = 0;
337 rt2x00dev->link.vgc_level = 0; 384 memset(qual, 0, sizeof(*qual));
338 385
339 /* 386 /*
340 * Reset the link tuner. 387 * Reset the link tuner.
341 */ 388 */
342 rt2x00dev->ops->lib->reset_tuner(rt2x00dev); 389 rt2x00dev->ops->lib->reset_tuner(rt2x00dev, qual);
343 390
344 if (antenna) 391 if (antenna)
345 rt2x00link_antenna_reset(rt2x00dev); 392 rt2x00link_antenna_reset(rt2x00dev);
@@ -349,6 +396,7 @@ static void rt2x00link_tuner(struct work_struct *work)
349{ 396{
350 struct rt2x00_dev *rt2x00dev = 397 struct rt2x00_dev *rt2x00dev =
351 container_of(work, struct rt2x00_dev, link.work.work); 398 container_of(work, struct rt2x00_dev, link.work.work);
399 struct link *link = &rt2x00dev->link;
352 struct link_qual *qual = &rt2x00dev->link.qual; 400 struct link_qual *qual = &rt2x00dev->link.qual;
353 401
354 /* 402 /*
@@ -365,11 +413,22 @@ static void rt2x00link_tuner(struct work_struct *work)
365 rt2x00dev->low_level_stats.dot11FCSErrorCount += qual->rx_failed; 413 rt2x00dev->low_level_stats.dot11FCSErrorCount += qual->rx_failed;
366 414
367 /* 415 /*
416 * Update quality RSSI for link tuning,
417 * when we have received some frames and we managed to
418 * collect the RSSI data we could use this. Otherwise we
419 * must fallback to the default RSSI value.
420 */
421 if (!link->avg_rssi || !qual->rx_success)
422 qual->rssi = DEFAULT_RSSI;
423 else
424 qual->rssi = link->avg_rssi;
425
426 /*
368 * Only perform the link tuning when Link tuning 427 * Only perform the link tuning when Link tuning
369 * has been enabled (This could have been disabled from the EEPROM). 428 * has been enabled (This could have been disabled from the EEPROM).
370 */ 429 */
371 if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags)) 430 if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
372 rt2x00dev->ops->lib->link_tuner(rt2x00dev); 431 rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
373 432
374 /* 433 /*
375 * Precalculate a portion of the link signal which is 434 * Precalculate a portion of the link signal which is
@@ -380,7 +439,7 @@ static void rt2x00link_tuner(struct work_struct *work)
380 /* 439 /*
381 * Send a signal to the led to update the led signal strength. 440 * Send a signal to the led to update the led signal strength.
382 */ 441 */
383 rt2x00leds_led_quality(rt2x00dev, qual->avg_rssi); 442 rt2x00leds_led_quality(rt2x00dev, link->avg_rssi);
384 443
385 /* 444 /*
386 * Evaluate antenna setup, make this the last step since this could 445 * Evaluate antenna setup, make this the last step since this could
@@ -391,9 +450,9 @@ static void rt2x00link_tuner(struct work_struct *work)
391 /* 450 /*
392 * Increase tuner counter, and reschedule the next link tuner run. 451 * Increase tuner counter, and reschedule the next link tuner run.
393 */ 452 */
394 rt2x00dev->link.count++; 453 link->count++;
395 queue_delayed_work(rt2x00dev->hw->workqueue, 454 queue_delayed_work(rt2x00dev->hw->workqueue,
396 &rt2x00dev->link.work, LINK_TUNE_INTERVAL); 455 &link->work, LINK_TUNE_INTERVAL);
397} 456}
398 457
399void rt2x00link_register(struct rt2x00_dev *rt2x00dev) 458void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 94523f7f0d88..ed829879c941 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1046,24 +1046,25 @@ static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev,
1046 qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); 1046 qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
1047} 1047}
1048 1048
1049static inline void rt61pci_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level) 1049static inline void rt61pci_set_vgc(struct rt2x00_dev *rt2x00dev,
1050 struct link_qual *qual, u8 vgc_level)
1050{ 1051{
1051 if (rt2x00dev->link.vgc_level != vgc_level) { 1052 if (qual->vgc_level != vgc_level) {
1052 rt61pci_bbp_write(rt2x00dev, 17, vgc_level); 1053 rt61pci_bbp_write(rt2x00dev, 17, vgc_level);
1053 rt2x00dev->link.vgc_level = vgc_level; 1054 qual->vgc_level = vgc_level;
1054 rt2x00dev->link.vgc_level_reg = vgc_level; 1055 qual->vgc_level_reg = vgc_level;
1055 } 1056 }
1056} 1057}
1057 1058
1058static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev) 1059static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
1060 struct link_qual *qual)
1059{ 1061{
1060 rt61pci_set_vgc(rt2x00dev, 0x20); 1062 rt61pci_set_vgc(rt2x00dev, qual, 0x20);
1061} 1063}
1062 1064
1063static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) 1065static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev,
1066 struct link_qual *qual, const u32 count)
1064{ 1067{
1065 struct link *link = &rt2x00dev->link;
1066 int rssi = rt2x00_get_link_rssi(link);
1067 u8 up_bound; 1068 u8 up_bound;
1068 u8 low_bound; 1069 u8 low_bound;
1069 1070
@@ -1096,32 +1097,32 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
1096 /* 1097 /*
1097 * Special big-R17 for very short distance 1098 * Special big-R17 for very short distance
1098 */ 1099 */
1099 if (rssi >= -35) { 1100 if (qual->rssi >= -35) {
1100 rt61pci_set_vgc(rt2x00dev, 0x60); 1101 rt61pci_set_vgc(rt2x00dev, qual, 0x60);
1101 return; 1102 return;
1102 } 1103 }
1103 1104
1104 /* 1105 /*
1105 * Special big-R17 for short distance 1106 * Special big-R17 for short distance
1106 */ 1107 */
1107 if (rssi >= -58) { 1108 if (qual->rssi >= -58) {
1108 rt61pci_set_vgc(rt2x00dev, up_bound); 1109 rt61pci_set_vgc(rt2x00dev, qual, up_bound);
1109 return; 1110 return;
1110 } 1111 }
1111 1112
1112 /* 1113 /*
1113 * Special big-R17 for middle-short distance 1114 * Special big-R17 for middle-short distance
1114 */ 1115 */
1115 if (rssi >= -66) { 1116 if (qual->rssi >= -66) {
1116 rt61pci_set_vgc(rt2x00dev, low_bound + 0x10); 1117 rt61pci_set_vgc(rt2x00dev, qual, low_bound + 0x10);
1117 return; 1118 return;
1118 } 1119 }
1119 1120
1120 /* 1121 /*
1121 * Special mid-R17 for middle distance 1122 * Special mid-R17 for middle distance
1122 */ 1123 */
1123 if (rssi >= -74) { 1124 if (qual->rssi >= -74) {
1124 rt61pci_set_vgc(rt2x00dev, low_bound + 0x08); 1125 rt61pci_set_vgc(rt2x00dev, qual, low_bound + 0x08);
1125 return; 1126 return;
1126 } 1127 }
1127 1128
@@ -1129,12 +1130,12 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
1129 * Special case: Change up_bound based on the rssi. 1130 * Special case: Change up_bound based on the rssi.
1130 * Lower up_bound when rssi is weaker then -74 dBm. 1131 * Lower up_bound when rssi is weaker then -74 dBm.
1131 */ 1132 */
1132 up_bound -= 2 * (-74 - rssi); 1133 up_bound -= 2 * (-74 - qual->rssi);
1133 if (low_bound > up_bound) 1134 if (low_bound > up_bound)
1134 up_bound = low_bound; 1135 up_bound = low_bound;
1135 1136
1136 if (link->vgc_level > up_bound) { 1137 if (qual->vgc_level > up_bound) {
1137 rt61pci_set_vgc(rt2x00dev, up_bound); 1138 rt61pci_set_vgc(rt2x00dev, qual, up_bound);
1138 return; 1139 return;
1139 } 1140 }
1140 1141
@@ -1144,10 +1145,10 @@ dynamic_cca_tune:
1144 * r17 does not yet exceed upper limit, continue and base 1145 * r17 does not yet exceed upper limit, continue and base
1145 * the r17 tuning on the false CCA count. 1146 * the r17 tuning on the false CCA count.
1146 */ 1147 */
1147 if ((link->qual.false_cca > 512) && (link->vgc_level < up_bound)) 1148 if ((qual->false_cca > 512) && (qual->vgc_level < up_bound))
1148 rt61pci_set_vgc(rt2x00dev, ++link->vgc_level); 1149 rt61pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level);
1149 else if ((link->qual.false_cca < 100) && (link->vgc_level > low_bound)) 1150 else if ((qual->false_cca < 100) && (qual->vgc_level > low_bound))
1150 rt61pci_set_vgc(rt2x00dev, --link->vgc_level); 1151 rt61pci_set_vgc(rt2x00dev, qual, --qual->vgc_level);
1151} 1152}
1152 1153
1153/* 1154/*
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index b5443148d621..e99bcacfc191 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -924,24 +924,25 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev,
924 qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); 924 qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
925} 925}
926 926
927static inline void rt73usb_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level) 927static inline void rt73usb_set_vgc(struct rt2x00_dev *rt2x00dev,
928 struct link_qual *qual, u8 vgc_level)
928{ 929{
929 if (rt2x00dev->link.vgc_level != vgc_level) { 930 if (qual->vgc_level != vgc_level) {
930 rt73usb_bbp_write(rt2x00dev, 17, vgc_level); 931 rt73usb_bbp_write(rt2x00dev, 17, vgc_level);
931 rt2x00dev->link.vgc_level = vgc_level; 932 qual->vgc_level = vgc_level;
932 rt2x00dev->link.vgc_level_reg = vgc_level; 933 qual->vgc_level_reg = vgc_level;
933 } 934 }
934} 935}
935 936
936static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev) 937static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev,
938 struct link_qual *qual)
937{ 939{
938 rt73usb_set_vgc(rt2x00dev, 0x20); 940 rt73usb_set_vgc(rt2x00dev, qual, 0x20);
939} 941}
940 942
941static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) 943static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev,
944 struct link_qual *qual, const u32 count)
942{ 945{
943 struct link *link = &rt2x00dev->link;
944 int rssi = rt2x00_get_link_rssi(link);
945 u8 up_bound; 946 u8 up_bound;
946 u8 low_bound; 947 u8 low_bound;
947 948
@@ -957,10 +958,10 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
957 up_bound += 0x10; 958 up_bound += 0x10;
958 } 959 }
959 } else { 960 } else {
960 if (rssi > -82) { 961 if (qual->rssi > -82) {
961 low_bound = 0x1c; 962 low_bound = 0x1c;
962 up_bound = 0x40; 963 up_bound = 0x40;
963 } else if (rssi > -84) { 964 } else if (qual->rssi > -84) {
964 low_bound = 0x1c; 965 low_bound = 0x1c;
965 up_bound = 0x20; 966 up_bound = 0x20;
966 } else { 967 } else {
@@ -984,32 +985,32 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
984 /* 985 /*
985 * Special big-R17 for very short distance 986 * Special big-R17 for very short distance
986 */ 987 */
987 if (rssi > -35) { 988 if (qual->rssi > -35) {
988 rt73usb_set_vgc(rt2x00dev, 0x60); 989 rt73usb_set_vgc(rt2x00dev, qual, 0x60);
989 return; 990 return;
990 } 991 }
991 992
992 /* 993 /*
993 * Special big-R17 for short distance 994 * Special big-R17 for short distance
994 */ 995 */
995 if (rssi >= -58) { 996 if (qual->rssi >= -58) {
996 rt73usb_set_vgc(rt2x00dev, up_bound); 997 rt73usb_set_vgc(rt2x00dev, qual, up_bound);
997 return; 998 return;
998 } 999 }
999 1000
1000 /* 1001 /*
1001 * Special big-R17 for middle-short distance 1002 * Special big-R17 for middle-short distance
1002 */ 1003 */
1003 if (rssi >= -66) { 1004 if (qual->rssi >= -66) {
1004 rt73usb_set_vgc(rt2x00dev, low_bound + 0x10); 1005 rt73usb_set_vgc(rt2x00dev, qual, low_bound + 0x10);
1005 return; 1006 return;
1006 } 1007 }
1007 1008
1008 /* 1009 /*
1009 * Special mid-R17 for middle distance 1010 * Special mid-R17 for middle distance
1010 */ 1011 */
1011 if (rssi >= -74) { 1012 if (qual->rssi >= -74) {
1012 rt73usb_set_vgc(rt2x00dev, low_bound + 0x08); 1013 rt73usb_set_vgc(rt2x00dev, qual, low_bound + 0x08);
1013 return; 1014 return;
1014 } 1015 }
1015 1016
@@ -1017,12 +1018,12 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
1017 * Special case: Change up_bound based on the rssi. 1018 * Special case: Change up_bound based on the rssi.
1018 * Lower up_bound when rssi is weaker then -74 dBm. 1019 * Lower up_bound when rssi is weaker then -74 dBm.
1019 */ 1020 */
1020 up_bound -= 2 * (-74 - rssi); 1021 up_bound -= 2 * (-74 - qual->rssi);
1021 if (low_bound > up_bound) 1022 if (low_bound > up_bound)
1022 up_bound = low_bound; 1023 up_bound = low_bound;
1023 1024
1024 if (link->vgc_level > up_bound) { 1025 if (qual->vgc_level > up_bound) {
1025 rt73usb_set_vgc(rt2x00dev, up_bound); 1026 rt73usb_set_vgc(rt2x00dev, qual, up_bound);
1026 return; 1027 return;
1027 } 1028 }
1028 1029
@@ -1032,12 +1033,12 @@ dynamic_cca_tune:
1032 * r17 does not yet exceed upper limit, continue and base 1033 * r17 does not yet exceed upper limit, continue and base
1033 * the r17 tuning on the false CCA count. 1034 * the r17 tuning on the false CCA count.
1034 */ 1035 */
1035 if ((link->qual.false_cca > 512) && (link->vgc_level < up_bound)) 1036 if ((qual->false_cca > 512) && (qual->vgc_level < up_bound))
1036 rt73usb_set_vgc(rt2x00dev, 1037 rt73usb_set_vgc(rt2x00dev, qual,
1037 min_t(u8, link->vgc_level + 4, up_bound)); 1038 min_t(u8, qual->vgc_level + 4, up_bound));
1038 else if ((link->qual.false_cca < 100) && (link->vgc_level > low_bound)) 1039 else if ((qual->false_cca < 100) && (qual->vgc_level > low_bound))
1039 rt73usb_set_vgc(rt2x00dev, 1040 rt73usb_set_vgc(rt2x00dev, qual,
1040 max_t(u8, link->vgc_level - 4, low_bound)); 1041 max_t(u8, qual->vgc_level - 4, low_bound));
1041} 1042}
1042 1043
1043/* 1044/*