aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2008-12-20 04:54:54 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 15:58:35 -0500
commit5352ff6510422d9a9bf13b7272f865eb53247f4d (patch)
treeec85fd9933b3d79cf4ae844c36f0803168203f06 /drivers
parenteb20b4e8a6998ca68d9ac0963ee36a1a36fe241d (diff)
rt2x00: Restrict interface between rt2x00link and drivers
Restrict drivers to only access link_qual structure during link tuning. The contents of these fields are for the drivers and all fields are allowed to be changed to values the driver considers correct. This means that some fields need to be moved outside of this structure to restrict access only to rt2x00link itself. This allows some code to be moved outside of the rt2x00.h header and into rt2x00link.c. Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-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 e87ad43e8e8..9104113270d 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 5b98a74a255..fb86e2c5524 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 23cf585f03a..557fcf2b30e 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 8935f2c005c..dea502234cf 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 0462d5ab6e9..ee08f1167f5 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 94523f7f0d8..ed829879c94 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 b5443148d62..e99bcacfc19 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/*