rt2x00link.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /*
  2. Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
  3. <http://rt2x00.serialmonkey.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the
  14. Free Software Foundation, Inc.,
  15. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  16. */
  17. /*
  18. Module: rt2x00lib
  19. Abstract: rt2x00 generic link tuning routines.
  20. */
  21. #include <linux/kernel.h>
  22. #include <linux/module.h>
  23. #include "rt2x00.h"
  24. #include "rt2x00lib.h"
  25. /*
  26. * When we lack RSSI information return something less then -80 to
  27. * tell the driver to tune the device to maximum sensitivity.
  28. */
  29. #define DEFAULT_RSSI -128
  30. /*
  31. * When no TX/RX percentage could be calculated due to lack of
  32. * frames on the air, we fallback to a percentage of 50%.
  33. * This will assure we will get at least get some decent value
  34. * when the link tuner starts.
  35. * The value will be dropped and overwritten with the correct (measured)
  36. * value anyway during the first run of the link tuner.
  37. */
  38. #define DEFAULT_PERCENTAGE 50
  39. /*
  40. * Small helper macro to work with moving/walking averages.
  41. * When adding a value to the average value the following calculation
  42. * is needed:
  43. *
  44. * avg_rssi = ((avg_rssi * 7) + rssi) / 8;
  45. *
  46. * The advantage of this approach is that we only need 1 variable
  47. * to store the average in (No need for a count and a total).
  48. * But more importantly, normal average values will over time
  49. * move less and less towards newly added values this results
  50. * that with link tuning, the device can have a very good RSSI
  51. * for a few minutes but when the device is moved away from the AP
  52. * the average will not decrease fast enough to compensate.
  53. * The walking average compensates this and will move towards
  54. * the new values correctly allowing a effective link tuning.
  55. */
  56. #define MOVING_AVERAGE(__avg, __val, __samples) \
  57. ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) )
  58. /*
  59. * Small helper macro for percentage calculation
  60. * This is a very simple macro with the only catch that it will
  61. * produce a default value in case no total value was provided.
  62. */
  63. #define PERCENTAGE(__value, __total) \
  64. ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) )
  65. /*
  66. * For calculating the Signal quality we have determined
  67. * the total number of success and failed RX and TX frames.
  68. * With the addition of the average RSSI value we can determine
  69. * the link quality using the following algorithm:
  70. *
  71. * rssi_percentage = (avg_rssi * 100) / rssi_offset
  72. * rx_percentage = (rx_success * 100) / rx_total
  73. * tx_percentage = (tx_success * 100) / tx_total
  74. * avg_signal = ((WEIGHT_RSSI * avg_rssi) +
  75. * (WEIGHT_TX * tx_percentage) +
  76. * (WEIGHT_RX * rx_percentage)) / 100
  77. *
  78. * This value should then be checked to not be greater then 100.
  79. * This means the values of WEIGHT_RSSI, WEIGHT_RX, WEIGHT_TX must
  80. * sum up to 100 as well.
  81. */
  82. #define WEIGHT_RSSI 20
  83. #define WEIGHT_RX 40
  84. #define WEIGHT_TX 40
  85. static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
  86. {
  87. struct link_ant *ant = &rt2x00dev->link.ant;
  88. if (ant->rssi_ant && rt2x00dev->link.qual.rx_success)
  89. return ant->rssi_ant;
  90. return DEFAULT_RSSI;
  91. }
  92. static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev,
  93. enum antenna antenna)
  94. {
  95. struct link_ant *ant = &rt2x00dev->link.ant;
  96. if (ant->rssi_history[antenna - ANTENNA_A])
  97. return ant->rssi_history[antenna - ANTENNA_A];
  98. return DEFAULT_RSSI;
  99. }
  100. /* Small wrapper for rt2x00link_antenna_get_rssi_history() */
  101. #define rt2x00link_antenna_get_rssi_rx_history(__dev) \
  102. rt2x00link_antenna_get_rssi_history((__dev), \
  103. (__dev)->link.ant.active.rx)
  104. #define rt2x00link_antenna_get_rssi_tx_history(__dev) \
  105. rt2x00link_antenna_get_rssi_history((__dev), \
  106. (__dev)->link.ant.active.tx)
  107. static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
  108. enum antenna antenna,
  109. int rssi)
  110. {
  111. struct link_ant *ant = &rt2x00dev->link.ant;
  112. ant->rssi_history[ant->active.rx - ANTENNA_A] = rssi;
  113. }
  114. /* Small wrapper for rt2x00link_antenna_get_rssi_history() */
  115. #define rt2x00link_antenna_update_rssi_rx_history(__dev, __rssi) \
  116. rt2x00link_antenna_update_rssi_history((__dev), \
  117. (__dev)->link.ant.active.rx, \
  118. (__rssi))
  119. #define rt2x00link_antenna_update_rssi_tx_history(__dev, __rssi) \
  120. rt2x00link_antenna_update_rssi_history((__dev), \
  121. (__dev)->link.ant.active.tx, \
  122. (__rssi))
  123. static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
  124. {
  125. rt2x00dev->link.ant.rssi_ant = 0;
  126. }
  127. static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
  128. {
  129. struct link_ant *ant = &rt2x00dev->link.ant;
  130. struct antenna_setup new_ant;
  131. int sample_a = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_A);
  132. int sample_b = rt2x00link_antenna_get_rssi_history(rt2x00dev, ANTENNA_B);
  133. memcpy(&new_ant, &ant->active, sizeof(new_ant));
  134. /*
  135. * We are done sampling. Now we should evaluate the results.
  136. */
  137. ant->flags &= ~ANTENNA_MODE_SAMPLE;
  138. /*
  139. * During the last period we have sampled the RSSI
  140. * from both antenna's. It now is time to determine
  141. * which antenna demonstrated the best performance.
  142. * When we are already on the antenna with the best
  143. * performance, then there really is nothing for us
  144. * left to do.
  145. */
  146. if (sample_a == sample_b)
  147. return;
  148. if (ant->flags & ANTENNA_RX_DIVERSITY)
  149. new_ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
  150. if (ant->flags & ANTENNA_TX_DIVERSITY)
  151. new_ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
  152. rt2x00lib_config_antenna(rt2x00dev, &new_ant);
  153. }
  154. static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
  155. {
  156. struct link_ant *ant = &rt2x00dev->link.ant;
  157. struct antenna_setup new_ant;
  158. int rssi_curr;
  159. int rssi_old;
  160. memcpy(&new_ant, &ant->active, sizeof(new_ant));
  161. /*
  162. * Get current RSSI value along with the historical value,
  163. * after that update the history with the current value.
  164. */
  165. rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev);
  166. rssi_old = rt2x00link_antenna_get_rssi_rx_history(rt2x00dev);
  167. rt2x00link_antenna_update_rssi_rx_history(rt2x00dev, rssi_curr);
  168. /*
  169. * Legacy driver indicates that we should swap antenna's
  170. * when the difference in RSSI is greater that 5. This
  171. * also should be done when the RSSI was actually better
  172. * then the previous sample.
  173. * When the difference exceeds the threshold we should
  174. * sample the rssi from the other antenna to make a valid
  175. * comparison between the 2 antennas.
  176. */
  177. if (abs(rssi_curr - rssi_old) < 5)
  178. return;
  179. ant->flags |= ANTENNA_MODE_SAMPLE;
  180. if (ant->flags & ANTENNA_RX_DIVERSITY)
  181. new_ant.rx = (new_ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
  182. if (ant->flags & ANTENNA_TX_DIVERSITY)
  183. new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
  184. rt2x00lib_config_antenna(rt2x00dev, &new_ant);
  185. }
  186. static void rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
  187. {
  188. struct link_ant *ant = &rt2x00dev->link.ant;
  189. /*
  190. * Determine if software diversity is enabled for
  191. * either the TX or RX antenna (or both).
  192. * Always perform this check since within the link
  193. * tuner interval the configuration might have changed.
  194. */
  195. ant->flags &= ~ANTENNA_RX_DIVERSITY;
  196. ant->flags &= ~ANTENNA_TX_DIVERSITY;
  197. if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
  198. ant->flags |= ANTENNA_RX_DIVERSITY;
  199. if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
  200. ant->flags |= ANTENNA_TX_DIVERSITY;
  201. if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
  202. !(ant->flags & ANTENNA_TX_DIVERSITY)) {
  203. ant->flags = 0;
  204. return;
  205. }
  206. /*
  207. * If we have only sampled the data over the last period
  208. * we should now harvest the data. Otherwise just evaluate
  209. * the data. The latter should only be performed once
  210. * every 2 seconds.
  211. */
  212. if (ant->flags & ANTENNA_MODE_SAMPLE)
  213. rt2x00lib_antenna_diversity_sample(rt2x00dev);
  214. else if (rt2x00dev->link.count & 1)
  215. rt2x00lib_antenna_diversity_eval(rt2x00dev);
  216. }
  217. void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
  218. struct sk_buff *skb,
  219. struct rxdone_entry_desc *rxdesc)
  220. {
  221. struct link *link = &rt2x00dev->link;
  222. struct link_qual *qual = &rt2x00dev->link.qual;
  223. struct link_ant *ant = &rt2x00dev->link.ant;
  224. struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
  225. int avg_rssi = rxdesc->rssi;
  226. int ant_rssi = rxdesc->rssi;
  227. /*
  228. * Frame was received successfully since non-succesfull
  229. * frames would have been dropped by the hardware.
  230. */
  231. qual->rx_success++;
  232. /*
  233. * We are only interested in quality statistics from
  234. * beacons which came from the BSS which we are
  235. * associated with.
  236. */
  237. if (!ieee80211_is_beacon(hdr->frame_control) ||
  238. !(rxdesc->dev_flags & RXDONE_MY_BSS))
  239. return;
  240. /*
  241. * Update global RSSI
  242. */
  243. if (link->avg_rssi)
  244. avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi, 8);
  245. link->avg_rssi = avg_rssi;
  246. /*
  247. * Update antenna RSSI
  248. */
  249. if (ant->rssi_ant)
  250. ant_rssi = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi, 8);
  251. ant->rssi_ant = ant_rssi;
  252. }
  253. static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
  254. {
  255. struct link *link = &rt2x00dev->link;
  256. struct link_qual *qual = &rt2x00dev->link.qual;
  257. link->rx_percentage =
  258. PERCENTAGE(qual->rx_success, qual->rx_failed + qual->rx_success);
  259. link->tx_percentage =
  260. PERCENTAGE(qual->tx_success, qual->tx_failed + qual->tx_success);
  261. }
  262. int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi)
  263. {
  264. struct link *link = &rt2x00dev->link;
  265. int rssi_percentage = 0;
  266. int signal;
  267. /*
  268. * We need a positive value for the RSSI.
  269. */
  270. if (rssi < 0)
  271. rssi += rt2x00dev->rssi_offset;
  272. /*
  273. * Calculate the different percentages,
  274. * which will be used for the signal.
  275. */
  276. rssi_percentage = PERCENTAGE(rssi, rt2x00dev->rssi_offset);
  277. /*
  278. * Add the individual percentages and use the WEIGHT
  279. * defines to calculate the current link signal.
  280. */
  281. signal = ((WEIGHT_RSSI * rssi_percentage) +
  282. (WEIGHT_TX * link->tx_percentage) +
  283. (WEIGHT_RX * link->rx_percentage)) / 100;
  284. return max_t(int, signal, 100);
  285. }
  286. void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
  287. {
  288. struct link *link = &rt2x00dev->link;
  289. /*
  290. * Link tuning should only be performed when
  291. * an active sta or master interface exists.
  292. * Single monitor mode interfaces should never have
  293. * work with link tuners.
  294. */
  295. if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
  296. return;
  297. link->rx_percentage = DEFAULT_PERCENTAGE;
  298. link->tx_percentage = DEFAULT_PERCENTAGE;
  299. rt2x00link_reset_tuner(rt2x00dev, false);
  300. queue_delayed_work(rt2x00dev->hw->workqueue,
  301. &link->work, LINK_TUNE_INTERVAL);
  302. }
  303. void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
  304. {
  305. cancel_delayed_work_sync(&rt2x00dev->link.work);
  306. }
  307. void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
  308. {
  309. struct link_qual *qual = &rt2x00dev->link.qual;
  310. if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
  311. return;
  312. /*
  313. * Reset link information.
  314. * Both the currently active vgc level as well as
  315. * the link tuner counter should be reset. Resetting
  316. * the counter is important for devices where the
  317. * device should only perform link tuning during the
  318. * first minute after being enabled.
  319. */
  320. rt2x00dev->link.count = 0;
  321. memset(qual, 0, sizeof(*qual));
  322. /*
  323. * Reset the link tuner.
  324. */
  325. rt2x00dev->ops->lib->reset_tuner(rt2x00dev, qual);
  326. if (antenna)
  327. rt2x00link_antenna_reset(rt2x00dev);
  328. }
  329. void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev)
  330. {
  331. struct link_qual *qual = &rt2x00dev->link.qual;
  332. qual->rx_success = 0;
  333. qual->rx_failed = 0;
  334. qual->tx_success = 0;
  335. qual->tx_failed = 0;
  336. }
  337. static void rt2x00link_tuner(struct work_struct *work)
  338. {
  339. struct rt2x00_dev *rt2x00dev =
  340. container_of(work, struct rt2x00_dev, link.work.work);
  341. struct link *link = &rt2x00dev->link;
  342. struct link_qual *qual = &rt2x00dev->link.qual;
  343. /*
  344. * When the radio is shutting down we should
  345. * immediately cease all link tuning.
  346. */
  347. if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
  348. return;
  349. /*
  350. * Update statistics.
  351. */
  352. rt2x00dev->ops->lib->link_stats(rt2x00dev, qual);
  353. rt2x00dev->low_level_stats.dot11FCSErrorCount += qual->rx_failed;
  354. /*
  355. * Update quality RSSI for link tuning,
  356. * when we have received some frames and we managed to
  357. * collect the RSSI data we could use this. Otherwise we
  358. * must fallback to the default RSSI value.
  359. */
  360. if (!link->avg_rssi || !qual->rx_success)
  361. qual->rssi = DEFAULT_RSSI;
  362. else
  363. qual->rssi = link->avg_rssi;
  364. /*
  365. * Only perform the link tuning when Link tuning
  366. * has been enabled (This could have been disabled from the EEPROM).
  367. */
  368. if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
  369. rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
  370. /*
  371. * Precalculate a portion of the link signal which is
  372. * in based on the tx/rx success/failure counters.
  373. */
  374. rt2x00link_precalculate_signal(rt2x00dev);
  375. /*
  376. * Send a signal to the led to update the led signal strength.
  377. */
  378. rt2x00leds_led_quality(rt2x00dev, link->avg_rssi);
  379. /*
  380. * Evaluate antenna setup, make this the last step since this could
  381. * possibly reset some statistics.
  382. */
  383. rt2x00lib_antenna_diversity(rt2x00dev);
  384. /*
  385. * Reset the quality counters which recounted during each period.
  386. */
  387. rt2x00link_reset_qual(rt2x00dev);
  388. /*
  389. * Increase tuner counter, and reschedule the next link tuner run.
  390. */
  391. link->count++;
  392. queue_delayed_work(rt2x00dev->hw->workqueue,
  393. &link->work, LINK_TUNE_INTERVAL);
  394. }
  395. void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
  396. {
  397. INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
  398. }