/* * Copyright (c) 2004-2008 Reyk Floeter <[email protected]> * Copyright (c) 2006-2008 Nick Kossifidis <[email protected]> * Copyright (c) 2007-2008 Matthew W. S. Bell <[email protected]> * Copyright (c) 2007-2008 Luis Rodriguez <[email protected]> * Copyright (c) 2007-2008 Pavel Roskin <[email protected]> * Copyright (c) 2007-2008 Jiri Slaby <[email protected]> * * Permission to use, copy, modify, and 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. * */ /*********************************\ * Protocol Control Unit Functions * \*********************************/ #include <asm/unaligned.h> #include "ath5k.h" #include "reg.h" #include "debug.h" /** * DOC: Protocol Control Unit (PCU) functions * * Protocol control unit is responsible to maintain various protocol * properties before a frame is send and after a frame is received to/from * baseband. To be more specific, PCU handles: * * - Buffering of RX and TX frames (after QCU/DCUs) * * - Encrypting and decrypting (using the built-in engine) * * - Generating ACKs, RTS/CTS frames * * - Maintaining TSF * * - FCS * * - Updating beacon data (with TSF etc) * * - Generating virtual CCA * * - RX/Multicast filtering * * - BSSID filtering * * - Various statistics * * -Different operating modes: AP, STA, IBSS * * Note: Most of these functions can be tweaked/bypassed so you can do * them on sw above for debugging or research. For more infos check out PCU * registers on reg.h. */ /** * DOC: ACK rates * * AR5212+ can use higher rates for ack transmission * based on current tx rate instead of the base rate. * It does this to better utilize channel usage. * There is a mapping between G rates (that cover both * CCK and OFDM) and ack rates that we use when setting * rate -> duration table. This mapping is hw-based so * don't change anything. * * To enable this functionality we must set * ah->ah_ack_bitrate_high to true else base rate is * used (1Mb for CCK, 6Mb for OFDM). */ static const unsigned int ack_rates_high[] = …/* Tx -> ACK */ /* 1Mb -> 1Mb */ { … }; /*******************\ * Helper functions * \*******************/ /** * ath5k_hw_get_frame_duration() - Get tx time of a frame * @ah: The &struct ath5k_hw * @band: One of enum nl80211_band * @len: Frame's length in bytes * @rate: The @struct ieee80211_rate * @shortpre: Indicate short preample * * Calculate tx duration of a frame given it's rate and length * It extends ieee80211_generic_frame_duration for non standard * bwmodes. */ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, enum nl80211_band band, int len, struct ieee80211_rate *rate, bool shortpre) { … } /** * ath5k_hw_get_default_slottime() - Get the default slot time for current mode * @ah: The &struct ath5k_hw */ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) { … } /** * ath5k_hw_get_default_sifs() - Get the default SIFS for current mode * @ah: The &struct ath5k_hw */ unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) { … } /** * ath5k_hw_update_mib_counters() - Update MIB counters (mac layer statistics) * @ah: The &struct ath5k_hw * * Reads MIB counters from PCU and updates sw statistics. Is called after a * MIB interrupt, because one of these counters might have reached their maximum * and triggered the MIB interrupt, to let us read and clear the counter. * * NOTE: Is called in interrupt context! */ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah) { … } /******************\ * ACK/CTS Timeouts * \******************/ /** * ath5k_hw_write_rate_duration() - Fill rate code to duration table * @ah: The &struct ath5k_hw * * Write the rate code to duration table upon hw reset. This is a helper for * ath5k_hw_pcu_init(). It seems all this is doing is setting an ACK timeout on * the hardware, based on current mode, for each rate. The rates which are * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have * different rate code so we write their value twice (one for long preamble * and one for short). * * Note: Band doesn't matter here, if we set the values for OFDM it works * on both a and g modes. So all we have to do is set values for all g rates * that include all OFDM and CCK rates. * */ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah) { … } /** * ath5k_hw_set_ack_timeout() - Set ACK timeout on PCU * @ah: The &struct ath5k_hw * @timeout: Timeout in usec */ static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) { … } /** * ath5k_hw_set_cts_timeout() - Set CTS timeout on PCU * @ah: The &struct ath5k_hw * @timeout: Timeout in usec */ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) { … } /*******************\ * RX filter Control * \*******************/ /** * ath5k_hw_set_lladdr() - Set station id * @ah: The &struct ath5k_hw * @mac: The card's mac address (array of octets) * * Set station id on hw using the provided mac address */ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) { … } /** * ath5k_hw_set_bssid() - Set current BSSID on hw * @ah: The &struct ath5k_hw * * Sets the current BSSID and BSSID mask we have from the * common struct into the hardware */ void ath5k_hw_set_bssid(struct ath5k_hw *ah) { … } /** * ath5k_hw_set_bssid_mask() - Filter out bssids we listen * @ah: The &struct ath5k_hw * @mask: The BSSID mask to set (array of octets) * * BSSID masking is a method used by AR5212 and newer hardware to inform PCU * which bits of the interface's MAC address should be looked at when trying * to decide which packets to ACK. In station mode and AP mode with a single * BSS every bit matters since we lock to only one BSS. In AP mode with * multiple BSSes (virtual interfaces) not every bit matters because hw must * accept frames for all BSSes and so we tweak some bits of our mac address * in order to have multiple BSSes. * * For more information check out ../hw.c of the common ath module. */ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) { … } /** * ath5k_hw_set_mcast_filter() - Set multicast filter * @ah: The &struct ath5k_hw * @filter0: Lower 32bits of muticast filter * @filter1: Higher 16bits of multicast filter */ void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) { … } /** * ath5k_hw_get_rx_filter() - Get current rx filter * @ah: The &struct ath5k_hw * * Returns the RX filter by reading rx filter and * phy error filter registers. RX filter is used * to set the allowed frame types that PCU will accept * and pass to the driver. For a list of frame types * check out reg.h. */ u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) { … } /** * ath5k_hw_set_rx_filter() - Set rx filter * @ah: The &struct ath5k_hw * @filter: RX filter mask (see reg.h) * * Sets RX filter register and also handles PHY error filter * register on 5212 and newer chips so that we have proper PHY * error reporting. */ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) { … } /****************\ * Beacon control * \****************/ #define ATH5K_MAX_TSF_READ … /** * ath5k_hw_get_tsf64() - Get the full 64bit TSF * @ah: The &struct ath5k_hw * * Returns the current TSF */ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) { … } #undef ATH5K_MAX_TSF_READ /** * ath5k_hw_set_tsf64() - Set a new 64bit TSF * @ah: The &struct ath5k_hw * @tsf64: The new 64bit TSF * * Sets the new TSF */ void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64) { … } /** * ath5k_hw_reset_tsf() - Force a TSF reset * @ah: The &struct ath5k_hw * * Forces a TSF reset on PCU */ void ath5k_hw_reset_tsf(struct ath5k_hw *ah) { … } /** * ath5k_hw_init_beacon_timers() - Initialize beacon timers * @ah: The &struct ath5k_hw * @next_beacon: Next TBTT * @interval: Current beacon interval * * This function is used to initialize beacon timers based on current * operation mode and settings. */ void ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon, u32 interval) { … } /** * ath5k_check_timer_win() - Check if timer B is timer A + window * @a: timer a (before b) * @b: timer b (after a) * @window: difference between a and b * @intval: timers are increased by this interval * * This helper function checks if timer B is timer A + window and covers * cases where timer A or B might have already been updated or wrapped * around (Timers are 16 bit). * * Returns true if O.K. */ static inline bool ath5k_check_timer_win(int a, int b, int window, int intval) { … } /** * ath5k_hw_check_beacon_timers() - Check if the beacon timers are correct * @ah: The &struct ath5k_hw * @intval: beacon interval * * This is a workaround for IBSS mode * * The need for this function arises from the fact that we have 4 separate * HW timer registers (TIMER0 - TIMER3), which are closely related to the * next beacon target time (NBTT), and that the HW updates these timers * separately based on the current TSF value. The hardware increments each * timer by the beacon interval, when the local TSF converted to TU is equal * to the value stored in the timer. * * The reception of a beacon with the same BSSID can update the local HW TSF * at any time - this is something we can't avoid. If the TSF jumps to a * time which is later than the time stored in a timer, this timer will not * be updated until the TSF in TU wraps around at 16 bit (the size of the * timers) and reaches the time which is stored in the timer. * * The problem is that these timers are closely related to TIMER0 (NBTT) and * that they define a time "window". When the TSF jumps between two timers * (e.g. ATIM and NBTT), the one in the past will be left behind (not * updated), while the one in the future will be updated every beacon * interval. This causes the window to get larger, until the TSF wraps * around as described above and the timer which was left behind gets * updated again. But - because the beacon interval is usually not an exact * divisor of the size of the timers (16 bit), an unwanted "window" between * these timers has developed! * * This is especially important with the ATIM window, because during * the ATIM window only ATIM frames and no data frames are allowed to be * sent, which creates transmission pauses after each beacon. This symptom * has been described as "ramping ping" because ping times increase linearly * for some time and then drop down again. A wrong window on the DMA beacon * timer has the same effect, so we check for these two conditions. * * Returns true if O.K. */ bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval) { … } /** * ath5k_hw_set_coverage_class() - Set IEEE 802.11 coverage class * @ah: The &struct ath5k_hw * @coverage_class: IEEE 802.11 coverage class number * * Sets IFS intervals and ACK/CTS timeouts for given coverage class. */ void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) { … } /***************************\ * Init/Start/Stop functions * \***************************/ /** * ath5k_hw_start_rx_pcu() - Start RX engine * @ah: The &struct ath5k_hw * * Starts RX engine on PCU so that hw can process RXed frames * (ACK etc). * * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma */ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) { … } /** * ath5k_hw_stop_rx_pcu() - Stop RX engine * @ah: The &struct ath5k_hw * * Stops RX engine on PCU */ void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) { … } /** * ath5k_hw_set_opmode() - Set PCU operating mode * @ah: The &struct ath5k_hw * @op_mode: One of enum nl80211_iftype * * Configure PCU for the various operating modes (AP/STA etc) */ int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) { … } /** * ath5k_hw_pcu_init() - Initialize PCU * @ah: The &struct ath5k_hw * @op_mode: One of enum nl80211_iftype * * This function is used to initialize PCU by setting current * operation mode and various other settings. */ void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode) { … }