root/drivers/net/wireless/ralink/rt2x00/rt2x00link.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rt2x00link_get_avg_rssi
  2. rt2x00link_antenna_get_link_rssi
  3. rt2x00link_antenna_get_rssi_history
  4. rt2x00link_antenna_update_rssi_history
  5. rt2x00link_antenna_reset
  6. rt2x00lib_antenna_diversity_sample
  7. rt2x00lib_antenna_diversity_eval
  8. rt2x00lib_antenna_diversity
  9. rt2x00link_update_stats
  10. rt2x00link_start_tuner
  11. rt2x00link_stop_tuner
  12. rt2x00link_reset_tuner
  13. rt2x00link_reset_qual
  14. rt2x00link_tuner_sta
  15. rt2x00link_tuner
  16. rt2x00link_start_watchdog
  17. rt2x00link_stop_watchdog
  18. rt2x00link_watchdog
  19. rt2x00link_register

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3         Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
   4         <http://rt2x00.serialmonkey.com>
   5 
   6  */
   7 
   8 /*
   9         Module: rt2x00lib
  10         Abstract: rt2x00 generic link tuning routines.
  11  */
  12 
  13 #include <linux/kernel.h>
  14 #include <linux/module.h>
  15 
  16 #include "rt2x00.h"
  17 #include "rt2x00lib.h"
  18 
  19 /*
  20  * When we lack RSSI information return something less then -80 to
  21  * tell the driver to tune the device to maximum sensitivity.
  22  */
  23 #define DEFAULT_RSSI            -128
  24 
  25 static inline int rt2x00link_get_avg_rssi(struct ewma_rssi *ewma)
  26 {
  27         unsigned long avg;
  28 
  29         avg = ewma_rssi_read(ewma);
  30         if (avg)
  31                 return -avg;
  32 
  33         return DEFAULT_RSSI;
  34 }
  35 
  36 static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
  37 {
  38         struct link_ant *ant = &rt2x00dev->link.ant;
  39 
  40         if (rt2x00dev->link.qual.rx_success)
  41                 return rt2x00link_get_avg_rssi(&ant->rssi_ant);
  42 
  43         return DEFAULT_RSSI;
  44 }
  45 
  46 static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev)
  47 {
  48         struct link_ant *ant = &rt2x00dev->link.ant;
  49 
  50         if (ant->rssi_history)
  51                 return ant->rssi_history;
  52         return DEFAULT_RSSI;
  53 }
  54 
  55 static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
  56                                                    int rssi)
  57 {
  58         struct link_ant *ant = &rt2x00dev->link.ant;
  59         ant->rssi_history = rssi;
  60 }
  61 
  62 static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
  63 {
  64         ewma_rssi_init(&rt2x00dev->link.ant.rssi_ant);
  65 }
  66 
  67 static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
  68 {
  69         struct link_ant *ant = &rt2x00dev->link.ant;
  70         struct antenna_setup new_ant;
  71         int other_antenna;
  72 
  73         int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev);
  74         int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev);
  75 
  76         memcpy(&new_ant, &ant->active, sizeof(new_ant));
  77 
  78         /*
  79          * We are done sampling. Now we should evaluate the results.
  80          */
  81         ant->flags &= ~ANTENNA_MODE_SAMPLE;
  82 
  83         /*
  84          * During the last period we have sampled the RSSI
  85          * from both antennas. It now is time to determine
  86          * which antenna demonstrated the best performance.
  87          * When we are already on the antenna with the best
  88          * performance, just create a good starting point
  89          * for the history and we are done.
  90          */
  91         if (sample_current >= sample_other) {
  92                 rt2x00link_antenna_update_rssi_history(rt2x00dev,
  93                         sample_current);
  94                 return;
  95         }
  96 
  97         other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
  98 
  99         if (ant->flags & ANTENNA_RX_DIVERSITY)
 100                 new_ant.rx = other_antenna;
 101 
 102         if (ant->flags & ANTENNA_TX_DIVERSITY)
 103                 new_ant.tx = other_antenna;
 104 
 105         rt2x00lib_config_antenna(rt2x00dev, new_ant);
 106 }
 107 
 108 static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
 109 {
 110         struct link_ant *ant = &rt2x00dev->link.ant;
 111         struct antenna_setup new_ant;
 112         int rssi_curr;
 113         int rssi_old;
 114 
 115         memcpy(&new_ant, &ant->active, sizeof(new_ant));
 116 
 117         /*
 118          * Get current RSSI value along with the historical value,
 119          * after that update the history with the current value.
 120          */
 121         rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev);
 122         rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev);
 123         rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr);
 124 
 125         /*
 126          * Legacy driver indicates that we should swap antenna's
 127          * when the difference in RSSI is greater that 5. This
 128          * also should be done when the RSSI was actually better
 129          * then the previous sample.
 130          * When the difference exceeds the threshold we should
 131          * sample the rssi from the other antenna to make a valid
 132          * comparison between the 2 antennas.
 133          */
 134         if (abs(rssi_curr - rssi_old) < 5)
 135                 return;
 136 
 137         ant->flags |= ANTENNA_MODE_SAMPLE;
 138 
 139         if (ant->flags & ANTENNA_RX_DIVERSITY)
 140                 new_ant.rx = (new_ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
 141 
 142         if (ant->flags & ANTENNA_TX_DIVERSITY)
 143                 new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
 144 
 145         rt2x00lib_config_antenna(rt2x00dev, new_ant);
 146 }
 147 
 148 static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
 149 {
 150         struct link_ant *ant = &rt2x00dev->link.ant;
 151 
 152         /*
 153          * Determine if software diversity is enabled for
 154          * either the TX or RX antenna (or both).
 155          */
 156         if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
 157             !(ant->flags & ANTENNA_TX_DIVERSITY)) {
 158                 ant->flags = 0;
 159                 return true;
 160         }
 161 
 162         /*
 163          * If we have only sampled the data over the last period
 164          * we should now harvest the data. Otherwise just evaluate
 165          * the data. The latter should only be performed once
 166          * every 2 seconds.
 167          */
 168         if (ant->flags & ANTENNA_MODE_SAMPLE) {
 169                 rt2x00lib_antenna_diversity_sample(rt2x00dev);
 170                 return true;
 171         } else if (rt2x00dev->link.count & 1) {
 172                 rt2x00lib_antenna_diversity_eval(rt2x00dev);
 173                 return true;
 174         }
 175 
 176         return false;
 177 }
 178 
 179 void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
 180                              struct sk_buff *skb,
 181                              struct rxdone_entry_desc *rxdesc)
 182 {
 183         struct link *link = &rt2x00dev->link;
 184         struct link_qual *qual = &rt2x00dev->link.qual;
 185         struct link_ant *ant = &rt2x00dev->link.ant;
 186         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 187 
 188         /*
 189          * No need to update the stats for !=STA interfaces
 190          */
 191         if (!rt2x00dev->intf_sta_count)
 192                 return;
 193 
 194         /*
 195          * Frame was received successfully since non-succesfull
 196          * frames would have been dropped by the hardware.
 197          */
 198         qual->rx_success++;
 199 
 200         /*
 201          * We are only interested in quality statistics from
 202          * beacons which came from the BSS which we are
 203          * associated with.
 204          */
 205         if (!ieee80211_is_beacon(hdr->frame_control) ||
 206             !(rxdesc->dev_flags & RXDONE_MY_BSS))
 207                 return;
 208 
 209         /*
 210          * Update global RSSI
 211          */
 212         ewma_rssi_add(&link->avg_rssi, -rxdesc->rssi);
 213 
 214         /*
 215          * Update antenna RSSI
 216          */
 217         ewma_rssi_add(&ant->rssi_ant, -rxdesc->rssi);
 218 }
 219 
 220 void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
 221 {
 222         struct link *link = &rt2x00dev->link;
 223 
 224         /*
 225          * Single monitor mode interfaces should never have
 226          * work with link tuners.
 227          */
 228         if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
 229                 return;
 230 
 231         /*
 232          * While scanning, link tuning is disabled. By default
 233          * the most sensitive settings will be used to make sure
 234          * that all beacons and probe responses will be received
 235          * during the scan.
 236          */
 237         if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
 238                 return;
 239 
 240         rt2x00link_reset_tuner(rt2x00dev, false);
 241 
 242         if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
 243                 ieee80211_queue_delayed_work(rt2x00dev->hw,
 244                                              &link->work, LINK_TUNE_INTERVAL);
 245 }
 246 
 247 void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
 248 {
 249         cancel_delayed_work_sync(&rt2x00dev->link.work);
 250 }
 251 
 252 void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
 253 {
 254         struct link_qual *qual = &rt2x00dev->link.qual;
 255         u8 vgc_level = qual->vgc_level_reg;
 256 
 257         if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 258                 return;
 259 
 260         /*
 261          * Reset link information.
 262          * Both the currently active vgc level as well as
 263          * the link tuner counter should be reset. Resetting
 264          * the counter is important for devices where the
 265          * device should only perform link tuning during the
 266          * first minute after being enabled.
 267          */
 268         rt2x00dev->link.count = 0;
 269         memset(qual, 0, sizeof(*qual));
 270         ewma_rssi_init(&rt2x00dev->link.avg_rssi);
 271 
 272         /*
 273          * Restore the VGC level as stored in the registers,
 274          * the driver can use this to determine if the register
 275          * must be updated during reset or not.
 276          */
 277         qual->vgc_level_reg = vgc_level;
 278 
 279         /*
 280          * Reset the link tuner.
 281          */
 282         rt2x00dev->ops->lib->reset_tuner(rt2x00dev, qual);
 283 
 284         if (antenna)
 285                 rt2x00link_antenna_reset(rt2x00dev);
 286 }
 287 
 288 static void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev)
 289 {
 290         struct link_qual *qual = &rt2x00dev->link.qual;
 291 
 292         qual->rx_success = 0;
 293         qual->rx_failed = 0;
 294         qual->tx_success = 0;
 295         qual->tx_failed = 0;
 296 }
 297 
 298 static void rt2x00link_tuner_sta(struct rt2x00_dev *rt2x00dev, struct link *link)
 299 {
 300         struct link_qual *qual = &rt2x00dev->link.qual;
 301 
 302         /*
 303          * Update statistics.
 304          */
 305         rt2x00dev->ops->lib->link_stats(rt2x00dev, qual);
 306         rt2x00dev->low_level_stats.dot11FCSErrorCount += qual->rx_failed;
 307 
 308         /*
 309          * Update quality RSSI for link tuning,
 310          * when we have received some frames and we managed to
 311          * collect the RSSI data we could use this. Otherwise we
 312          * must fallback to the default RSSI value.
 313          */
 314         if (!qual->rx_success)
 315                 qual->rssi = DEFAULT_RSSI;
 316         else
 317                 qual->rssi = rt2x00link_get_avg_rssi(&link->avg_rssi);
 318 
 319         /*
 320          * Check if link tuning is supported by the hardware, some hardware
 321          * do not support link tuning at all, while other devices can disable
 322          * the feature from the EEPROM.
 323          */
 324         if (rt2x00_has_cap_link_tuning(rt2x00dev))
 325                 rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
 326 
 327         /*
 328          * Send a signal to the led to update the led signal strength.
 329          */
 330         rt2x00leds_led_quality(rt2x00dev, qual->rssi);
 331 
 332         /*
 333          * Evaluate antenna setup, make this the last step when
 334          * rt2x00lib_antenna_diversity made changes the quality
 335          * statistics will be reset.
 336          */
 337         if (rt2x00lib_antenna_diversity(rt2x00dev))
 338                 rt2x00link_reset_qual(rt2x00dev);
 339 }
 340 
 341 static void rt2x00link_tuner(struct work_struct *work)
 342 {
 343         struct rt2x00_dev *rt2x00dev =
 344             container_of(work, struct rt2x00_dev, link.work.work);
 345         struct link *link = &rt2x00dev->link;
 346 
 347         /*
 348          * When the radio is shutting down we should
 349          * immediately cease all link tuning.
 350          */
 351         if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
 352             test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
 353                 return;
 354 
 355         /* Do not race with rt2x00mac_config(). */
 356         mutex_lock(&rt2x00dev->conf_mutex);
 357 
 358         if (rt2x00dev->intf_sta_count)
 359                 rt2x00link_tuner_sta(rt2x00dev, link);
 360 
 361         if (rt2x00dev->ops->lib->gain_calibration &&
 362             (link->count % (AGC_SECONDS / LINK_TUNE_SECONDS)) == 0)
 363                 rt2x00dev->ops->lib->gain_calibration(rt2x00dev);
 364 
 365         if (rt2x00dev->ops->lib->vco_calibration &&
 366             rt2x00_has_cap_vco_recalibration(rt2x00dev) &&
 367             (link->count % (VCO_SECONDS / LINK_TUNE_SECONDS)) == 0)
 368                 rt2x00dev->ops->lib->vco_calibration(rt2x00dev);
 369 
 370         mutex_unlock(&rt2x00dev->conf_mutex);
 371 
 372         /*
 373          * Increase tuner counter, and reschedule the next link tuner run.
 374          */
 375         link->count++;
 376 
 377         if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
 378                 ieee80211_queue_delayed_work(rt2x00dev->hw,
 379                                              &link->work, LINK_TUNE_INTERVAL);
 380 }
 381 
 382 void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
 383 {
 384         struct link *link = &rt2x00dev->link;
 385 
 386         if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
 387             rt2x00dev->ops->lib->watchdog && !link->watchdog_disabled)
 388                 ieee80211_queue_delayed_work(rt2x00dev->hw,
 389                                              &link->watchdog_work,
 390                                              link->watchdog_interval);
 391 }
 392 
 393 void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
 394 {
 395         cancel_delayed_work_sync(&rt2x00dev->link.watchdog_work);
 396 }
 397 
 398 static void rt2x00link_watchdog(struct work_struct *work)
 399 {
 400         struct rt2x00_dev *rt2x00dev =
 401             container_of(work, struct rt2x00_dev, link.watchdog_work.work);
 402         struct link *link = &rt2x00dev->link;
 403 
 404         /*
 405          * When the radio is shutting down we should
 406          * immediately cease the watchdog monitoring.
 407          */
 408         if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 409                 return;
 410 
 411         rt2x00dev->ops->lib->watchdog(rt2x00dev);
 412 
 413         if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
 414                 ieee80211_queue_delayed_work(rt2x00dev->hw,
 415                                              &link->watchdog_work,
 416                                              link->watchdog_interval);
 417 }
 418 
 419 void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
 420 {
 421         struct link *link = &rt2x00dev->link;
 422 
 423         INIT_DELAYED_WORK(&link->work, rt2x00link_tuner);
 424         INIT_DELAYED_WORK(&link->watchdog_work, rt2x00link_watchdog);
 425 
 426         if (link->watchdog_interval == 0)
 427                 link->watchdog_interval = WATCHDOG_INTERVAL;
 428 }

/* [<][>][^][v][top][bottom][index][help] */