/* * Copyright (C) 2010 Bruno Randolf <[email protected]> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define pr_fmt(fmt) … #include "ath5k.h" #include "reg.h" #include "debug.h" #include "ani.h" /** * DOC: Basic ANI Operation * * Adaptive Noise Immunity (ANI) controls five noise immunity parameters * depending on the amount of interference in the environment, increasing * or reducing sensitivity as necessary. * * The parameters are: * * - "noise immunity" * * - "spur immunity" * * - "firstep level" * * - "OFDM weak signal detection" * * - "CCK weak signal detection" * * Basically we look at the amount of ODFM and CCK timing errors we get and then * raise or lower immunity accordingly by setting one or more of these * parameters. * * Newer chipsets have PHY error counters in hardware which will generate a MIB * interrupt when they overflow. Older hardware has too enable PHY error frames * by setting a RX flag and then count every single PHY error. When a specified * threshold of errors has been reached we will raise immunity. * Also we regularly check the amount of errors and lower or raise immunity as * necessary. */ /***********************\ * ANI parameter control * \***********************/ /** * ath5k_ani_set_noise_immunity_level() - Set noise immunity level * @ah: The &struct ath5k_hw * @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL */ void ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) { … } /** * ath5k_ani_set_spur_immunity_level() - Set spur immunity level * @ah: The &struct ath5k_hw * @level: level between 0 and @max_spur_level (the maximum level is dependent * on the chip revision). */ void ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) { … } /** * ath5k_ani_set_firstep_level() - Set "firstep" level * @ah: The &struct ath5k_hw * @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL */ void ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level) { … } /** * ath5k_ani_set_ofdm_weak_signal_detection() - Set OFDM weak signal detection * @ah: The &struct ath5k_hw * @on: turn on or off */ void ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on) { … } /** * ath5k_ani_set_cck_weak_signal_detection() - Set CCK weak signal detection * @ah: The &struct ath5k_hw * @on: turn on or off */ void ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on) { … } /***************\ * ANI algorithm * \***************/ /** * ath5k_ani_raise_immunity() - Increase noise immunity * @ah: The &struct ath5k_hw * @as: The &struct ath5k_ani_state * @ofdm_trigger: If this is true we are called because of too many OFDM errors, * the algorithm will tune more parameters then. * * Try to raise noise immunity (=decrease sensitivity) in several steps * depending on the average RSSI of the beacons we received. */ static void ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, bool ofdm_trigger) { … } /** * ath5k_ani_lower_immunity() - Decrease noise immunity * @ah: The &struct ath5k_hw * @as: The &struct ath5k_ani_state * * Try to lower noise immunity (=increase sensitivity) in several steps * depending on the average RSSI of the beacons we received. */ static void ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) { … } /** * ath5k_hw_ani_get_listen_time() - Update counters and return listening time * @ah: The &struct ath5k_hw * @as: The &struct ath5k_ani_state * * Return an approximation of the time spent "listening" in milliseconds (ms) * since the last call of this function. * Save a snapshot of the counter values for debugging/statistics. */ static int ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as) { … } /** * ath5k_ani_save_and_clear_phy_errors() - Clear and save PHY error counters * @ah: The &struct ath5k_hw * @as: The &struct ath5k_ani_state * * Clear the PHY error counters as soon as possible, since this might be called * from a MIB interrupt and we want to make sure we don't get interrupted again. * Add the count of CCK and OFDM errors to our internal state, so it can be used * by the algorithm later. * * Will be called from interrupt and tasklet context. * Returns 0 if both counters are zero. */ static int ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah, struct ath5k_ani_state *as) { … } /** * ath5k_ani_period_restart() - Restart ANI period * @as: The &struct ath5k_ani_state * * Just reset counters, so they are clear for the next "ani period". */ static void ath5k_ani_period_restart(struct ath5k_ani_state *as) { … } /** * ath5k_ani_calibration() - The main ANI calibration function * @ah: The &struct ath5k_hw * * We count OFDM and CCK errors relative to the time where we did not send or * receive ("listen" time) and raise or lower immunity accordingly. * This is called regularly (every second) from the calibration timer, but also * when an error threshold has been reached. * * In order to synchronize access from different contexts, this should be * called only indirectly by scheduling the ANI tasklet! */ void ath5k_ani_calibration(struct ath5k_hw *ah) { … } /*******************\ * Interrupt handler * \*******************/ /** * ath5k_ani_mib_intr() - Interrupt handler for ANI MIB counters * @ah: The &struct ath5k_hw * * Just read & reset the registers quickly, so they don't generate more * interrupts, save the counters and schedule the tasklet to decide whether * to raise immunity or not. * * We just need to handle PHY error counters, ath5k_hw_update_mib_counters() * should take care of all "normal" MIB interrupts. */ void ath5k_ani_mib_intr(struct ath5k_hw *ah) { … } /** * ath5k_ani_phy_error_report - Used by older HW to report PHY errors * * @ah: The &struct ath5k_hw * @phyerr: One of enum ath5k_phy_error_code * * This is used by hardware without PHY error counters to report PHY errors * on a frame-by-frame basis, instead of the interrupt. */ void ath5k_ani_phy_error_report(struct ath5k_hw *ah, enum ath5k_phy_error_code phyerr) { … } /****************\ * Initialization * \****************/ /** * ath5k_enable_phy_err_counters() - Enable PHY error counters * @ah: The &struct ath5k_hw * * Enable PHY error counters for OFDM and CCK timing errors. */ static void ath5k_enable_phy_err_counters(struct ath5k_hw *ah) { … } /** * ath5k_disable_phy_err_counters() - Disable PHY error counters * @ah: The &struct ath5k_hw * * Disable PHY error counters for OFDM and CCK timing errors. */ static void ath5k_disable_phy_err_counters(struct ath5k_hw *ah) { … } /** * ath5k_ani_init() - Initialize ANI * @ah: The &struct ath5k_hw * @mode: One of enum ath5k_ani_mode * * Initialize ANI according to mode. */ void ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode) { … } /**************\ * Debug output * \**************/ #ifdef CONFIG_ATH5K_DEBUG /** * ath5k_ani_print_counters() - Print ANI counters * @ah: The &struct ath5k_hw * * Used for debugging ANI */ void ath5k_ani_print_counters(struct ath5k_hw *ah) { … } #endif