Skip to content

Commit

Permalink
rt2x00: Restrict interface between rt2x00link and drivers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ivo van Doorn authored and John W. Linville committed Jan 29, 2009
1 parent eb20b4e commit 5352ff6
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 199 deletions.
27 changes: 14 additions & 13 deletions 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 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 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 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 5352ff6

Please sign in to comment.