Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 133968
b: refs/heads/master
c: 5352ff6
h: refs/heads/master
v: v3
  • Loading branch information
Ivo van Doorn authored and John W. Linville committed Jan 29, 2009
1 parent 632e6d0 commit 8caf67f
Show file tree
Hide file tree
Showing 8 changed files with 234 additions and 200 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: eb20b4e8a6998ca68d9ac0963ee36a1a36fe241d
refs/heads/master: 5352ff6510422d9a9bf13b7272f865eb53247f4d
27 changes: 14 additions & 13 deletions trunk/drivers/net/wireless/rt2x00/rt2400pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -600,36 +600,37 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev,
qual->false_cca = bbp;
}

static inline void rt2400pci_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level)
static inline void rt2400pci_set_vgc(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, u8 vgc_level)
{
rt2400pci_bbp_write(rt2x00dev, 13, vgc_level);
rt2x00dev->link.vgc_level = vgc_level;
rt2x00dev->link.vgc_level_reg = vgc_level;
qual->vgc_level = vgc_level;
qual->vgc_level_reg = vgc_level;
}

static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual)
{
rt2400pci_set_vgc(rt2x00dev, 0x08);
rt2400pci_set_vgc(rt2x00dev, qual, 0x08);
}

static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, const u32 count)
{
struct link *link = &rt2x00dev->link;

/*
* The link tuner should not run longer then 60 seconds,
* and should run once every 2 seconds.
*/
if (link->count > 60 || !(link->count & 1))
if (count > 60 || !(count & 1))
return;

/*
* Base r13 link tuning on the false cca count.
*/
if ((link->qual.false_cca > 512) && (link->vgc_level < 0x20))
rt2400pci_set_vgc(rt2x00dev, ++link->vgc_level);
else if ((link->qual.false_cca < 100) && (link->vgc_level > 0x08))
rt2400pci_set_vgc(rt2x00dev, --link->vgc_level);
if ((qual->false_cca > 512) && (qual->vgc_level < 0x20))
rt2400pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level);
else if ((qual->false_cca < 100) && (qual->vgc_level > 0x08))
rt2400pci_set_vgc(rt2x00dev, qual, --qual->vgc_level);
}

/*
Expand Down
50 changes: 25 additions & 25 deletions trunk/drivers/net/wireless/rt2x00/rt2500pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -639,31 +639,31 @@ static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev,
qual->false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA);
}

static inline void rt2500pci_set_vgc(struct rt2x00_dev *rt2x00dev, u8 vgc_level)
static inline void rt2500pci_set_vgc(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, u8 vgc_level)
{
if (rt2x00dev->link.vgc_level_reg != vgc_level) {
if (qual->vgc_level_reg != vgc_level) {
rt2500pci_bbp_write(rt2x00dev, 17, vgc_level);
rt2x00dev->link.vgc_level_reg = vgc_level;
qual->vgc_level_reg = vgc_level;
}
}

static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual)
{
rt2500pci_set_vgc(rt2x00dev, 0x48);
rt2500pci_set_vgc(rt2x00dev, qual, 0x48);
}

static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, const u32 count)
{
struct link *link = &rt2x00dev->link;
int rssi = rt2x00_get_link_rssi(link);

/*
* To prevent collisions with MAC ASIC on chipsets
* up to version C the link tuning should halt after 20
* seconds while being associated.
*/
if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
rt2x00dev->intf_associated && link->count > 20)
rt2x00dev->intf_associated && count > 20)
return;

/*
Expand All @@ -681,34 +681,34 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* then corrupt the R17 tuning. To remidy this the tuning should
* be stopped (While making sure the R17 value will not exceed limits)
*/
if (rssi < -80 && link->count > 20) {
if (link->vgc_level_reg >= 0x41)
rt2500pci_set_vgc(rt2x00dev, link->vgc_level);
if (qual->rssi < -80 && count > 20) {
if (qual->vgc_level_reg >= 0x41)
rt2500pci_set_vgc(rt2x00dev, qual, qual->vgc_level);
return;
}

/*
* Special big-R17 for short distance
*/
if (rssi >= -58) {
rt2500pci_set_vgc(rt2x00dev, 0x50);
if (qual->rssi >= -58) {
rt2500pci_set_vgc(rt2x00dev, qual, 0x50);
return;
}

/*
* Special mid-R17 for middle distance
*/
if (rssi >= -74) {
rt2500pci_set_vgc(rt2x00dev, 0x41);
if (qual->rssi >= -74) {
rt2500pci_set_vgc(rt2x00dev, qual, 0x41);
return;
}

/*
* Leave short or middle distance condition, restore r17
* to the dynamic tuning range.
*/
if (link->vgc_level_reg >= 0x41) {
rt2500pci_set_vgc(rt2x00dev, link->vgc_level);
if (qual->vgc_level_reg >= 0x41) {
rt2500pci_set_vgc(rt2x00dev, qual, qual->vgc_level);
return;
}

Expand All @@ -718,12 +718,12 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
* R17 is inside the dynamic tuning range,
* start tuning the link based on the false cca counter.
*/
if (link->qual.false_cca > 512 && link->vgc_level_reg < 0x40) {
rt2500pci_set_vgc(rt2x00dev, ++link->vgc_level_reg);
link->vgc_level = link->vgc_level_reg;
} else if (link->qual.false_cca < 100 && link->vgc_level_reg > 0x32) {
rt2500pci_set_vgc(rt2x00dev, --link->vgc_level_reg);
link->vgc_level = link->vgc_level_reg;
if (qual->false_cca > 512 && qual->vgc_level_reg < 0x40) {
rt2500pci_set_vgc(rt2x00dev, qual, ++qual->vgc_level_reg);
qual->vgc_level = qual->vgc_level_reg;
} else if (qual->false_cca < 100 && qual->vgc_level_reg > 0x32) {
rt2500pci_set_vgc(rt2x00dev, qual, --qual->vgc_level_reg);
qual->vgc_level = qual->vgc_level_reg;
}
}

Expand Down
5 changes: 3 additions & 2 deletions trunk/drivers/net/wireless/rt2x00/rt2500usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,8 @@ static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev,
qual->false_cca = rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR);
}

static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual)
{
u16 eeprom;
u16 value;
Expand All @@ -719,7 +720,7 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_VGCUPPER);
rt2500usb_bbp_write(rt2x00dev, 17, value);

rt2x00dev->link.vgc_level = value;
qual->vgc_level = value;
}

/*
Expand Down
99 changes: 35 additions & 64 deletions trunk/drivers/net/wireless/rt2x00/rt2x00.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,52 +177,41 @@ struct antenna_setup {
*/
struct link_qual {
/*
* Statistics required for Link tuning.
* For the average RSSI value we use the "Walking average" approach.
* When adding RSSI to the average value the following calculation
* is needed:
*
* avg_rssi = ((avg_rssi * 7) + rssi) / 8;
* Statistics required for Link tuning by driver
* The rssi value is provided by rt2x00lib during the
* link_tuner() callback function.
* The false_cca field is filled during the link_stats()
* callback function and could be used during the
* link_tuner() callback function.
*/
int rssi;
int false_cca;

/*
* VGC levels
* Hardware driver will tune the VGC level during each call
* to the link_tuner() callback function. This vgc_level is
* is determined based on the link quality statistics like
* average RSSI and the false CCA count.
*
* The advantage of this approach is that we only need 1 variable
* to store the average in (No need for a count and a total).
* But more importantly, normal average values will over time
* move less and less towards newly added values this results
* that with link tuning, the device can have a very good RSSI
* for a few minutes but when the device is moved away from the AP
* the average will not decrease fast enough to compensate.
* The walking average compensates this and will move towards
* the new values correctly allowing a effective link tuning.
* In some cases the drivers need to differentiate between
* the currently "desired" VGC level and the level configured
* in the hardware. The latter is important to reduce the
* number of BBP register reads to reduce register access
* overhead. For this reason we store both values here.
*/
int avg_rssi;
int false_cca;
u8 vgc_level;
u8 vgc_level_reg;

/*
* Statistics required for Signal quality calculation.
* For calculating the Signal quality we have to determine
* the total number of success and failed RX and TX frames.
* After that we also use the average RSSI value to help
* determining the signal quality.
* For the calculation we will use the following algorithm:
*
* rssi_percentage = (avg_rssi * 100) / rssi_offset
* rx_percentage = (rx_success * 100) / rx_total
* tx_percentage = (tx_success * 100) / tx_total
* avg_signal = ((WEIGHT_RSSI * avg_rssi) +
* (WEIGHT_TX * tx_percentage) +
* (WEIGHT_RX * rx_percentage)) / 100
*
* This value should then be checked to not be greater then 100.
* These fields might be changed during the link_stats()
* callback function.
*/
int rx_percentage;
int rx_success;
int rx_failed;
int tx_percentage;
int tx_success;
int tx_failed;
#define WEIGHT_RSSI 20
#define WEIGHT_RX 40
#define WEIGHT_TX 40
};

/*
Expand Down Expand Up @@ -286,43 +275,23 @@ struct link {
struct link_ant ant;

/*
* Active VGC level (for false cca tuning)
* Currently active average RSSI value
*/
u8 vgc_level;
int avg_rssi;

/*
* VGC level as configured in register
* Currently precalculated percentages of successful
* TX and RX frames.
*/
u8 vgc_level_reg;
int rx_percentage;
int tx_percentage;

/*
* Work structure for scheduling periodic link tuning.
*/
struct delayed_work work;
};

/*
* Small helper macro to work with moving/walking averages.
*/
#define MOVING_AVERAGE(__avg, __val, __samples) \
( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) )

/*
* When we lack RSSI information return something less then -80 to
* tell the driver to tune the device to maximum sensitivity.
*/
#define DEFAULT_RSSI ( -128 )

/*
* Link quality access functions.
*/
static inline int rt2x00_get_link_rssi(struct link *link)
{
if (link->qual.avg_rssi && link->qual.rx_success)
return link->qual.avg_rssi;
return DEFAULT_RSSI;
}

/*
* Interface structure
* Per interface configuration details, this structure
Expand Down Expand Up @@ -522,8 +491,10 @@ struct rt2x00lib_ops {
int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev);
void (*link_stats) (struct rt2x00_dev *rt2x00dev,
struct link_qual *qual);
void (*reset_tuner) (struct rt2x00_dev *rt2x00dev);
void (*link_tuner) (struct rt2x00_dev *rt2x00dev);
void (*reset_tuner) (struct rt2x00_dev *rt2x00dev,
struct link_qual *qual);
void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, const u32 count);

/*
* TX control handlers
Expand Down
Loading

0 comments on commit 8caf67f

Please sign in to comment.