cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rt2x00link.c (11435B)


      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}