aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2007-10-13 10:26:36 -0400
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:02:53 -0500
commit69f81a2cac860cf183eb9ef7787525c3552d4612 (patch)
treeb149e55f1e21df8edf33046e662ce8f00834f1ac /drivers/net
parent8de8c5162b157884aa4855564cbfd9ec9119c819 (diff)
[PATCH] rt2x00: Implement SW diversity
When mac80211 indicates that the default antenna setup should be used _and_ that this default setup is SW_DIVERSITY. This requires sampling and storing the RSSI per antenna and check once every 2 seconds to determine if the RSSI has changed significantly. Once this is the case we should sample the other antenna for a short period and evaluate if we need to swap antenna or not. Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h87
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c26
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c138
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h2
4 files changed, 232 insertions, 21 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index d6f0a72b7a0c..e7533e2ccd2e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -241,6 +241,43 @@ struct link_qual {
241}; 241};
242 242
243/* 243/*
244 * Antenna settings about the currently active link.
245 */
246struct link_ant {
247 /*
248 * Antenna flags
249 */
250 unsigned int flags;
251#define ANTENNA_RX_DIVERSITY 0x00000001
252#define ANTENNA_TX_DIVERSITY 0x00000002
253#define ANTENNA_MODE_SAMPLE 0x00000004
254
255 /*
256 * Currently active TX/RX antenna setup.
257 * When software diversity is used, this will indicate
258 * which antenna is actually used at this time.
259 */
260 struct antenna_setup active;
261
262 /*
263 * RSSI information for the different antenna's.
264 * These statistics are used to determine when
265 * to switch antenna when using software diversity.
266 *
267 * rssi[0] -> Antenna A RSSI
268 * rssi[1] -> Antenna B RSSI
269 */
270 int rssi_history[2];
271
272 /*
273 * Current RSSI average of the currently active antenna.
274 * Similar to the avg_rssi in the link_qual structure
275 * this value is updated by using the walking average.
276 */
277 int rssi_ant;
278};
279
280/*
244 * To optimize the quality of the link we need to store 281 * To optimize the quality of the link we need to store
245 * the quality of received frames and periodically 282 * the quality of received frames and periodically
246 * optimize the link. 283 * optimize the link.
@@ -259,11 +296,9 @@ struct link {
259 struct link_qual qual; 296 struct link_qual qual;
260 297
261 /* 298 /*
262 * Currently active TX/RX antenna setup. 299 * TX/RX antenna setup.
263 * When software diversity is used, this will indicate
264 * which antenna is actually used at this time.
265 */ 300 */
266 struct antenna_setup active_ant; 301 struct link_ant ant;
267 302
268 /* 303 /*
269 * Active VGC level 304 * Active VGC level
@@ -277,25 +312,47 @@ struct link {
277}; 312};
278 313
279/* 314/*
280 * Update the rssi using the walking average approach. 315 * Small helper macro to work with moving/walking averages.
281 */ 316 */
282static inline void rt2x00_update_link_rssi(struct link *link, int rssi) 317#define MOVING_AVERAGE(__avg, __val, __samples) \
283{ 318 ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) )
284 if (link->qual.avg_rssi) 319
285 rssi = ((link->qual.avg_rssi * 7) + rssi) / 8; 320/*
286 link->qual.avg_rssi = rssi; 321 * When we lack RSSI information return something less then -80 to
287} 322 * tell the driver to tune the device to maximum sensitivity.
323 */
324#define DEFAULT_RSSI ( -128 )
288 325
289/* 326/*
290 * When the avg_rssi is unset or no frames have been received), 327 * Link quality access functions.
291 * we need to return the default value which needs to be less
292 * than -80 so the device will select the maximum sensitivity.
293 */ 328 */
294static inline int rt2x00_get_link_rssi(struct link *link) 329static inline int rt2x00_get_link_rssi(struct link *link)
295{ 330{
296 if (link->qual.avg_rssi && link->qual.rx_success) 331 if (link->qual.avg_rssi && link->qual.rx_success)
297 return link->qual.avg_rssi; 332 return link->qual.avg_rssi;
298 return -128; 333 return DEFAULT_RSSI;
334}
335
336static inline int rt2x00_get_link_ant_rssi(struct link *link)
337{
338 if (link->ant.rssi_ant && link->qual.rx_success)
339 return link->ant.rssi_ant;
340 return DEFAULT_RSSI;
341}
342
343static inline int rt2x00_get_link_ant_rssi_history(struct link *link,
344 enum antenna ant)
345{
346 if (link->ant.rssi_history[ant - ANTENNA_A])
347 return link->ant.rssi_history[ant - ANTENNA_A];
348 return DEFAULT_RSSI;
349}
350
351static inline int rt2x00_update_ant_rssi(struct link *link, int rssi)
352{
353 int old_rssi = link->ant.rssi_history[link->ant.active.rx - ANTENNA_A];
354 link->ant.rssi_history[link->ant.active.rx - ANTENNA_A] = rssi;
355 return old_rssi;
299} 356}
300 357
301/* 358/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 04518b089bdb..2b0edd20eea5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -94,6 +94,26 @@ void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type)
94 rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync); 94 rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync);
95} 95}
96 96
97void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
98 enum antenna rx, enum antenna tx)
99{
100 struct rt2x00lib_conf libconf;
101
102 libconf.ant.rx = rx;
103 libconf.ant.tx = tx;
104
105 /*
106 * Write new antenna setup to device and reset the link tuner.
107 * The latter is required since we need to recalibrate the
108 * noise-sensitivity ratio for the new setup.
109 */
110 rt2x00dev->ops->lib->config(rt2x00dev, CONFIG_UPDATE_ANTENNA, &libconf);
111 rt2x00lib_reset_link_tuner(rt2x00dev);
112
113 rt2x00dev->link.ant.active.rx = libconf.ant.rx;
114 rt2x00dev->link.ant.active.tx = libconf.ant.tx;
115}
116
97void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, 117void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
98 struct ieee80211_conf *conf, const int force_config) 118 struct ieee80211_conf *conf, const int force_config)
99{ 119{
@@ -101,7 +121,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
101 struct ieee80211_hw_mode *mode; 121 struct ieee80211_hw_mode *mode;
102 struct ieee80211_rate *rate; 122 struct ieee80211_rate *rate;
103 struct antenna_setup *default_ant = &rt2x00dev->default_ant; 123 struct antenna_setup *default_ant = &rt2x00dev->default_ant;
104 struct antenna_setup *active_ant = &rt2x00dev->link.active_ant; 124 struct antenna_setup *active_ant = &rt2x00dev->link.ant.active;
105 int flags = 0; 125 int flags = 0;
106 int short_slot_time; 126 int short_slot_time;
107 127
@@ -247,6 +267,6 @@ config:
247 rt2x00dev->rx_status.freq = conf->freq; 267 rt2x00dev->rx_status.freq = conf->freq;
248 rt2x00dev->rx_status.channel = conf->channel; 268 rt2x00dev->rx_status.channel = conf->channel;
249 rt2x00dev->tx_power = conf->power_level; 269 rt2x00dev->tx_power = conf->power_level;
250 rt2x00dev->link.active_ant.rx = libconf.ant.rx; 270 rt2x00dev->link.ant.active.rx = libconf.ant.rx;
251 rt2x00dev->link.active_ant.tx = libconf.ant.tx; 271 rt2x00dev->link.ant.active.tx = libconf.ant.tx;
252} 272}
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 0f824b27f1ef..360f03ae17a5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -193,6 +193,133 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state)
193 rt2x00lib_start_link_tuner(rt2x00dev); 193 rt2x00lib_start_link_tuner(rt2x00dev);
194} 194}
195 195
196static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev)
197{
198 enum antenna rx = rt2x00dev->link.ant.active.rx;
199 enum antenna tx = rt2x00dev->link.ant.active.tx;
200 int sample_a =
201 rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_A);
202 int sample_b =
203 rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_B);
204
205 /*
206 * We are done sampling. Now we should evaluate the results.
207 */
208 rt2x00dev->link.ant.flags &= ~ANTENNA_MODE_SAMPLE;
209
210 /*
211 * During the last period we have sampled the RSSI
212 * from both antenna's. It now is time to determine
213 * which antenna demonstrated the best performance.
214 * When we are already on the antenna with the best
215 * performance, then there really is nothing for us
216 * left to do.
217 */
218 if (sample_a == sample_b)
219 return;
220
221 if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) {
222 if (sample_a > sample_b && rx == ANTENNA_B)
223 rx = ANTENNA_A;
224 else if (rx == ANTENNA_A)
225 rx = ANTENNA_B;
226 }
227
228 if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) {
229 if (sample_a > sample_b && tx == ANTENNA_B)
230 tx = ANTENNA_A;
231 else if (tx == ANTENNA_A)
232 tx = ANTENNA_B;
233 }
234
235 rt2x00lib_config_antenna(rt2x00dev, rx, tx);
236}
237
238static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev)
239{
240 enum antenna rx = rt2x00dev->link.ant.active.rx;
241 enum antenna tx = rt2x00dev->link.ant.active.tx;
242 int rssi_curr = rt2x00_get_link_ant_rssi(&rt2x00dev->link);
243 int rssi_old = rt2x00_update_ant_rssi(&rt2x00dev->link, rssi_curr);
244
245 /*
246 * Legacy driver indicates that we should swap antenna's
247 * when the difference in RSSI is greater that 5. This
248 * also should be done when the RSSI was actually better
249 * then the previous sample.
250 * When the difference exceeds the threshold we should
251 * sample the rssi from the other antenna to make a valid
252 * comparison between the 2 antennas.
253 */
254 if ((rssi_curr - rssi_old) > -5 || (rssi_curr - rssi_old) < 5)
255 return;
256
257 rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE;
258
259 if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY)
260 rx = (rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
261
262 if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)
263 tx = (tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
264
265 rt2x00lib_config_antenna(rt2x00dev, rx, tx);
266}
267
268static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev)
269{
270 /*
271 * Determine if software diversity is enabled for
272 * either the TX or RX antenna (or both).
273 * Always perform this check since within the link
274 * tuner interval the configuration might have changed.
275 */
276 rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY;
277 rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY;
278
279 if (rt2x00dev->hw->conf.antenna_sel_rx == 0 &&
280 rt2x00dev->default_ant.rx != ANTENNA_SW_DIVERSITY)
281 rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY;
282 if (rt2x00dev->hw->conf.antenna_sel_tx == 0 &&
283 rt2x00dev->default_ant.tx != ANTENNA_SW_DIVERSITY)
284 rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY;
285
286 if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) &&
287 !(rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)) {
288 rt2x00dev->link.ant.flags &= ~ANTENNA_MODE_SAMPLE;
289 return;
290 }
291
292 /*
293 * If we have only sampled the data over the last period
294 * we should now harvest the data. Otherwise just evaluate
295 * the data. The latter should only be performed once
296 * every 2 seconds.
297 */
298 if (rt2x00dev->link.ant.flags & ANTENNA_MODE_SAMPLE)
299 rt2x00lib_evaluate_antenna_sample(rt2x00dev);
300 else if (rt2x00dev->link.count & 1)
301 rt2x00lib_evaluate_antenna_eval(rt2x00dev);
302}
303
304static void rt2x00lib_update_link_stats(struct link *link, int rssi)
305{
306 int avg_rssi = rssi;
307
308 /*
309 * Update global RSSI
310 */
311 if (link->qual.avg_rssi)
312 avg_rssi = MOVING_AVERAGE(link->qual.avg_rssi, rssi, 8);
313 link->qual.avg_rssi = avg_rssi;
314
315 /*
316 * Update antenna RSSI
317 */
318 if (link->ant.rssi_ant)
319 rssi = MOVING_AVERAGE(link->ant.rssi_ant, rssi, 8);
320 link->ant.rssi_ant = rssi;
321}
322
196static void rt2x00lib_precalculate_link_signal(struct link_qual *qual) 323static void rt2x00lib_precalculate_link_signal(struct link_qual *qual)
197{ 324{
198 if (qual->rx_failed || qual->rx_success) 325 if (qual->rx_failed || qual->rx_success)
@@ -261,7 +388,6 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
261 * Update statistics. 388 * Update statistics.
262 */ 389 */
263 rt2x00dev->ops->lib->link_stats(rt2x00dev, &rt2x00dev->link.qual); 390 rt2x00dev->ops->lib->link_stats(rt2x00dev, &rt2x00dev->link.qual);
264
265 rt2x00dev->low_level_stats.dot11FCSErrorCount += 391 rt2x00dev->low_level_stats.dot11FCSErrorCount +=
266 rt2x00dev->link.qual.rx_failed; 392 rt2x00dev->link.qual.rx_failed;
267 393
@@ -273,6 +399,11 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
273 rt2x00dev->ops->lib->link_tuner(rt2x00dev); 399 rt2x00dev->ops->lib->link_tuner(rt2x00dev);
274 400
275 /* 401 /*
402 * Evaluate antenna setup.
403 */
404 rt2x00lib_evaluate_antenna(rt2x00dev);
405
406 /*
276 * Precalculate a portion of the link signal which is 407 * Precalculate a portion of the link signal which is
277 * in based on the tx/rx success/failure counters. 408 * in based on the tx/rx success/failure counters.
278 */ 409 */
@@ -426,14 +557,15 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
426 } 557 }
427 } 558 }
428 559
429 rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi); 560 rt2x00lib_update_link_stats(&rt2x00dev->link, desc->rssi);
430 rt2x00dev->link.qual.rx_success++; 561 rt2x00dev->link.qual.rx_success++;
562
431 rx_status->rate = val; 563 rx_status->rate = val;
432 rx_status->signal = 564 rx_status->signal =
433 rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi); 565 rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi);
434 rx_status->ssi = desc->rssi; 566 rx_status->ssi = desc->rssi;
435 rx_status->flag = desc->flags; 567 rx_status->flag = desc->flags;
436 rx_status->antenna = rt2x00dev->link.active_ant.rx; 568 rx_status->antenna = rt2x00dev->link.ant.active.rx;
437 569
438 /* 570 /*
439 * Send frame to mac80211 571 * Send frame to mac80211
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 06d9bc0015c0..73194112f45c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -53,6 +53,8 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev);
53void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); 53void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac);
54void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); 54void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid);
55void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type); 55void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type);
56void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
57 enum antenna rx, enum antenna tx);
56void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, 58void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
57 struct ieee80211_conf *conf, const int force_config); 59 struct ieee80211_conf *conf, const int force_config);
58 60