linux/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
<<
>>
Prefs
   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
  25static 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
  36static 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
  46static 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
  55static 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
  62static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
  63{
  64        ewma_rssi_init(&rt2x00dev->link.ant.rssi_ant);
  65}
  66
  67static 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
 108static 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
 148static 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
 179void 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
 220void 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
 247void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
 248{
 249        cancel_delayed_work_sync(&rt2x00dev->link.work);
 250}
 251
 252void 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
 288static 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
 298static 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
 341static 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
 382void 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
 393void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
 394{
 395        cancel_delayed_work_sync(&rt2x00dev->link.watchdog_work);
 396}
 397
 398static 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
 419void 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}
 429