diff options
author | Ivo van Doorn <ivdoorn@gmail.com> | 2007-10-13 10:26:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:02:53 -0500 |
commit | 69f81a2cac860cf183eb9ef7787525c3552d4612 (patch) | |
tree | b149e55f1e21df8edf33046e662ce8f00834f1ac /drivers/net/wireless/rt2x00/rt2x00dev.c | |
parent | 8de8c5162b157884aa4855564cbfd9ec9119c819 (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/wireless/rt2x00/rt2x00dev.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 138 |
1 files changed, 135 insertions, 3 deletions
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 | ||
196 | static 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 | |||
238 | static 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 | |||
268 | static 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 | |||
304 | static 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 | |||
196 | static void rt2x00lib_precalculate_link_signal(struct link_qual *qual) | 323 | static 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 |