1db86f07eSLuis R. Rodriguez /* 25b68138eSSujith Manoharan * Copyright (c) 2009-2011 Atheros Communications Inc. 3db86f07eSLuis R. Rodriguez * 4db86f07eSLuis R. Rodriguez * Permission to use, copy, modify, and/or distribute this software for any 5db86f07eSLuis R. Rodriguez * purpose with or without fee is hereby granted, provided that the above 6db86f07eSLuis R. Rodriguez * copyright notice and this permission notice appear in all copies. 7db86f07eSLuis R. Rodriguez * 8db86f07eSLuis R. Rodriguez * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9db86f07eSLuis R. Rodriguez * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10db86f07eSLuis R. Rodriguez * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11db86f07eSLuis R. Rodriguez * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12db86f07eSLuis R. Rodriguez * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13db86f07eSLuis R. Rodriguez * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14db86f07eSLuis R. Rodriguez * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15db86f07eSLuis R. Rodriguez */ 16db86f07eSLuis R. Rodriguez 17db86f07eSLuis R. Rodriguez /* 18db86f07eSLuis R. Rodriguez * Module for common driver code between ath9k and ath9k_htc 19db86f07eSLuis R. Rodriguez */ 20db86f07eSLuis R. Rodriguez 21db86f07eSLuis R. Rodriguez #include <linux/kernel.h> 22db86f07eSLuis R. Rodriguez #include <linux/module.h> 23db86f07eSLuis R. Rodriguez 24db86f07eSLuis R. Rodriguez #include "common.h" 25db86f07eSLuis R. Rodriguez 26db86f07eSLuis R. Rodriguez MODULE_AUTHOR("Atheros Communications"); 27db86f07eSLuis R. Rodriguez MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards."); 28db86f07eSLuis R. Rodriguez MODULE_LICENSE("Dual BSD/GPL"); 29db86f07eSLuis R. Rodriguez 30*12746036SOleksij Rempel int ath9k_cmn_process_rate(struct ath_common *common, 31*12746036SOleksij Rempel struct ieee80211_hw *hw, 32*12746036SOleksij Rempel struct ath_rx_status *rx_stats, 33*12746036SOleksij Rempel struct ieee80211_rx_status *rxs) 34*12746036SOleksij Rempel { 35*12746036SOleksij Rempel struct ieee80211_supported_band *sband; 36*12746036SOleksij Rempel enum ieee80211_band band; 37*12746036SOleksij Rempel unsigned int i = 0; 38*12746036SOleksij Rempel struct ath_hw *ah = common->ah; 39*12746036SOleksij Rempel 40*12746036SOleksij Rempel band = ah->curchan->chan->band; 41*12746036SOleksij Rempel sband = hw->wiphy->bands[band]; 42*12746036SOleksij Rempel 43*12746036SOleksij Rempel if (IS_CHAN_QUARTER_RATE(ah->curchan)) 44*12746036SOleksij Rempel rxs->flag |= RX_FLAG_5MHZ; 45*12746036SOleksij Rempel else if (IS_CHAN_HALF_RATE(ah->curchan)) 46*12746036SOleksij Rempel rxs->flag |= RX_FLAG_10MHZ; 47*12746036SOleksij Rempel 48*12746036SOleksij Rempel if (rx_stats->rs_rate & 0x80) { 49*12746036SOleksij Rempel /* HT rate */ 50*12746036SOleksij Rempel rxs->flag |= RX_FLAG_HT; 51*12746036SOleksij Rempel rxs->flag |= rx_stats->flag; 52*12746036SOleksij Rempel rxs->rate_idx = rx_stats->rs_rate & 0x7f; 53*12746036SOleksij Rempel return 0; 54*12746036SOleksij Rempel } 55*12746036SOleksij Rempel 56*12746036SOleksij Rempel for (i = 0; i < sband->n_bitrates; i++) { 57*12746036SOleksij Rempel if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { 58*12746036SOleksij Rempel rxs->rate_idx = i; 59*12746036SOleksij Rempel return 0; 60*12746036SOleksij Rempel } 61*12746036SOleksij Rempel if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { 62*12746036SOleksij Rempel rxs->flag |= RX_FLAG_SHORTPRE; 63*12746036SOleksij Rempel rxs->rate_idx = i; 64*12746036SOleksij Rempel return 0; 65*12746036SOleksij Rempel } 66*12746036SOleksij Rempel } 67*12746036SOleksij Rempel 68*12746036SOleksij Rempel return -EINVAL; 69*12746036SOleksij Rempel } 70*12746036SOleksij Rempel EXPORT_SYMBOL(ath9k_cmn_process_rate); 71*12746036SOleksij Rempel 7232efb0ccSOleksij Rempel void ath9k_cmn_process_rssi(struct ath_common *common, 7332efb0ccSOleksij Rempel struct ieee80211_hw *hw, 7432efb0ccSOleksij Rempel struct ath_rx_status *rx_stats, 7532efb0ccSOleksij Rempel struct ieee80211_rx_status *rxs) 7632efb0ccSOleksij Rempel { 7732efb0ccSOleksij Rempel struct ath_hw *ah = common->ah; 7832efb0ccSOleksij Rempel int last_rssi; 7932efb0ccSOleksij Rempel int rssi = rx_stats->rs_rssi; 8032efb0ccSOleksij Rempel int i, j; 8132efb0ccSOleksij Rempel 8232efb0ccSOleksij Rempel /* 8332efb0ccSOleksij Rempel * RSSI is not available for subframes in an A-MPDU. 8432efb0ccSOleksij Rempel */ 8532efb0ccSOleksij Rempel if (rx_stats->rs_moreaggr) { 8632efb0ccSOleksij Rempel rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; 8732efb0ccSOleksij Rempel return; 8832efb0ccSOleksij Rempel } 8932efb0ccSOleksij Rempel 9032efb0ccSOleksij Rempel /* 9132efb0ccSOleksij Rempel * Check if the RSSI for the last subframe in an A-MPDU 9232efb0ccSOleksij Rempel * or an unaggregated frame is valid. 9332efb0ccSOleksij Rempel */ 9432efb0ccSOleksij Rempel if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) { 9532efb0ccSOleksij Rempel rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; 9632efb0ccSOleksij Rempel return; 9732efb0ccSOleksij Rempel } 9832efb0ccSOleksij Rempel 9932efb0ccSOleksij Rempel for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) { 10032efb0ccSOleksij Rempel s8 rssi; 10132efb0ccSOleksij Rempel 10232efb0ccSOleksij Rempel if (!(ah->rxchainmask & BIT(i))) 10332efb0ccSOleksij Rempel continue; 10432efb0ccSOleksij Rempel 10532efb0ccSOleksij Rempel rssi = rx_stats->rs_rssi_ctl[i]; 10632efb0ccSOleksij Rempel if (rssi != ATH9K_RSSI_BAD) { 10732efb0ccSOleksij Rempel rxs->chains |= BIT(j); 10832efb0ccSOleksij Rempel rxs->chain_signal[j] = ah->noise + rssi; 10932efb0ccSOleksij Rempel } 11032efb0ccSOleksij Rempel j++; 11132efb0ccSOleksij Rempel } 11232efb0ccSOleksij Rempel 11332efb0ccSOleksij Rempel /* 11432efb0ccSOleksij Rempel * Update Beacon RSSI, this is used by ANI. 11532efb0ccSOleksij Rempel */ 11632efb0ccSOleksij Rempel if (rx_stats->is_mybeacon && 11732efb0ccSOleksij Rempel ((ah->opmode == NL80211_IFTYPE_STATION) || 11832efb0ccSOleksij Rempel (ah->opmode == NL80211_IFTYPE_ADHOC))) { 11932efb0ccSOleksij Rempel ATH_RSSI_LPF(common->last_rssi, rx_stats->rs_rssi); 12032efb0ccSOleksij Rempel last_rssi = common->last_rssi; 12132efb0ccSOleksij Rempel 12232efb0ccSOleksij Rempel if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) 12332efb0ccSOleksij Rempel rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); 12432efb0ccSOleksij Rempel if (rssi < 0) 12532efb0ccSOleksij Rempel rssi = 0; 12632efb0ccSOleksij Rempel 12732efb0ccSOleksij Rempel ah->stats.avgbrssi = rssi; 12832efb0ccSOleksij Rempel } 12932efb0ccSOleksij Rempel 13032efb0ccSOleksij Rempel rxs->signal = ah->noise + rx_stats->rs_rssi; 13132efb0ccSOleksij Rempel } 13232efb0ccSOleksij Rempel EXPORT_SYMBOL(ath9k_cmn_process_rssi); 13332efb0ccSOleksij Rempel 134fb9987d0SSujith int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) 135fb9987d0SSujith { 136fb9987d0SSujith struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 137fb9987d0SSujith 138fb9987d0SSujith if (tx_info->control.hw_key) { 13997359d12SJohannes Berg switch (tx_info->control.hw_key->cipher) { 14097359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP40: 14197359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP104: 142fb9987d0SSujith return ATH9K_KEY_TYPE_WEP; 14397359d12SJohannes Berg case WLAN_CIPHER_SUITE_TKIP: 144fb9987d0SSujith return ATH9K_KEY_TYPE_TKIP; 14597359d12SJohannes Berg case WLAN_CIPHER_SUITE_CCMP: 146fb9987d0SSujith return ATH9K_KEY_TYPE_AES; 14797359d12SJohannes Berg default: 14897359d12SJohannes Berg break; 14997359d12SJohannes Berg } 150fb9987d0SSujith } 151fb9987d0SSujith 152fb9987d0SSujith return ATH9K_KEY_TYPE_CLEAR; 153fb9987d0SSujith } 154fb9987d0SSujith EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype); 155fb9987d0SSujith 156fb9987d0SSujith /* 157fb9987d0SSujith * Update internal channel flags. 158fb9987d0SSujith */ 1592297f1c7SFelix Fietkau static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, 1600671894fSSimon Wunderlich struct cfg80211_chan_def *chandef) 161fb9987d0SSujith { 1626b21fd20SFelix Fietkau struct ieee80211_channel *chan = chandef->chan; 1636b21fd20SFelix Fietkau u16 flags = 0; 164fb9987d0SSujith 1656b21fd20SFelix Fietkau ichan->channel = chan->center_freq; 1666b21fd20SFelix Fietkau ichan->chan = chan; 1676b21fd20SFelix Fietkau 1686b21fd20SFelix Fietkau if (chan->band == IEEE80211_BAND_5GHZ) 1696b21fd20SFelix Fietkau flags |= CHANNEL_5GHZ; 170fb9987d0SSujith 1710671894fSSimon Wunderlich switch (chandef->width) { 1720671894fSSimon Wunderlich case NL80211_CHAN_WIDTH_5: 1736b21fd20SFelix Fietkau flags |= CHANNEL_QUARTER; 1740671894fSSimon Wunderlich break; 1750671894fSSimon Wunderlich case NL80211_CHAN_WIDTH_10: 1766b21fd20SFelix Fietkau flags |= CHANNEL_HALF; 1770671894fSSimon Wunderlich break; 1780671894fSSimon Wunderlich case NL80211_CHAN_WIDTH_20_NOHT: 1790671894fSSimon Wunderlich break; 1800671894fSSimon Wunderlich case NL80211_CHAN_WIDTH_20: 1816b21fd20SFelix Fietkau flags |= CHANNEL_HT; 1826b21fd20SFelix Fietkau break; 1830671894fSSimon Wunderlich case NL80211_CHAN_WIDTH_40: 1846b21fd20SFelix Fietkau if (chandef->center_freq1 > chandef->chan->center_freq) 1856b21fd20SFelix Fietkau flags |= CHANNEL_HT40PLUS | CHANNEL_HT; 1866b21fd20SFelix Fietkau else 1876b21fd20SFelix Fietkau flags |= CHANNEL_HT40MINUS | CHANNEL_HT; 1880671894fSSimon Wunderlich break; 1890671894fSSimon Wunderlich default: 1900671894fSSimon Wunderlich WARN_ON(1); 1910671894fSSimon Wunderlich } 1926b21fd20SFelix Fietkau 1936b21fd20SFelix Fietkau ichan->channelFlags = flags; 194fb9987d0SSujith } 195fb9987d0SSujith 196fb9987d0SSujith /* 197fb9987d0SSujith * Get the internal channel reference. 198fb9987d0SSujith */ 1992297f1c7SFelix Fietkau struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw, 2002297f1c7SFelix Fietkau struct ath_hw *ah, 2012297f1c7SFelix Fietkau struct cfg80211_chan_def *chandef) 202fb9987d0SSujith { 2032297f1c7SFelix Fietkau struct ieee80211_channel *curchan = chandef->chan; 204fb9987d0SSujith struct ath9k_channel *channel; 205fb9987d0SSujith 206f40c4608SFelix Fietkau channel = &ah->channels[curchan->hw_value]; 2072297f1c7SFelix Fietkau ath9k_cmn_update_ichannel(channel, chandef); 208fb9987d0SSujith 209fb9987d0SSujith return channel; 210fb9987d0SSujith } 2112297f1c7SFelix Fietkau EXPORT_SYMBOL(ath9k_cmn_get_channel); 212fb9987d0SSujith 21361389f3eSSujith int ath9k_cmn_count_streams(unsigned int chainmask, int max) 21461389f3eSSujith { 21561389f3eSSujith int streams = 0; 21661389f3eSSujith 21761389f3eSSujith do { 21861389f3eSSujith if (++streams == max) 21961389f3eSSujith break; 22061389f3eSSujith } while ((chainmask = chainmask & (chainmask - 1))); 22161389f3eSSujith 22261389f3eSSujith return streams; 22361389f3eSSujith } 22461389f3eSSujith EXPORT_SYMBOL(ath9k_cmn_count_streams); 22561389f3eSSujith 2265048e8c3SRajkumar Manoharan void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, 2275048e8c3SRajkumar Manoharan u16 new_txpow, u16 *txpower) 2285048e8c3SRajkumar Manoharan { 229ca2c68ccSFelix Fietkau struct ath_regulatory *reg = ath9k_hw_regulatory(ah); 230ca2c68ccSFelix Fietkau 231ca2c68ccSFelix Fietkau if (reg->power_limit != new_txpow) { 2325048e8c3SRajkumar Manoharan ath9k_hw_set_txpowerlimit(ah, new_txpow, false); 2335048e8c3SRajkumar Manoharan /* read back in case value is clamped */ 234ca2c68ccSFelix Fietkau *txpower = reg->max_power_level; 2355048e8c3SRajkumar Manoharan } 2365048e8c3SRajkumar Manoharan } 2375048e8c3SRajkumar Manoharan EXPORT_SYMBOL(ath9k_cmn_update_txpow); 2385048e8c3SRajkumar Manoharan 239f82b4bdeSRajkumar Manoharan void ath9k_cmn_init_crypto(struct ath_hw *ah) 240f82b4bdeSRajkumar Manoharan { 241f82b4bdeSRajkumar Manoharan struct ath_common *common = ath9k_hw_common(ah); 242f82b4bdeSRajkumar Manoharan int i = 0; 243f82b4bdeSRajkumar Manoharan 244f82b4bdeSRajkumar Manoharan /* Get the hardware key cache size. */ 245f82b4bdeSRajkumar Manoharan common->keymax = AR_KEYTABLE_SIZE; 246f82b4bdeSRajkumar Manoharan 247f82b4bdeSRajkumar Manoharan /* 248f82b4bdeSRajkumar Manoharan * Check whether the separate key cache entries 249f82b4bdeSRajkumar Manoharan * are required to handle both tx+rx MIC keys. 250f82b4bdeSRajkumar Manoharan * With split mic keys the number of stations is limited 251f82b4bdeSRajkumar Manoharan * to 27 otherwise 59. 252f82b4bdeSRajkumar Manoharan */ 253f82b4bdeSRajkumar Manoharan if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) 254f82b4bdeSRajkumar Manoharan common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; 255f82b4bdeSRajkumar Manoharan 256f82b4bdeSRajkumar Manoharan /* 257f82b4bdeSRajkumar Manoharan * Reset the key cache since some parts do not 258f82b4bdeSRajkumar Manoharan * reset the contents on initial power up. 259f82b4bdeSRajkumar Manoharan */ 260f82b4bdeSRajkumar Manoharan for (i = 0; i < common->keymax; i++) 261f82b4bdeSRajkumar Manoharan ath_hw_keyreset(common, (u16) i); 262f82b4bdeSRajkumar Manoharan } 263f82b4bdeSRajkumar Manoharan EXPORT_SYMBOL(ath9k_cmn_init_crypto); 264f82b4bdeSRajkumar Manoharan 265db86f07eSLuis R. Rodriguez static int __init ath9k_cmn_init(void) 266db86f07eSLuis R. Rodriguez { 267db86f07eSLuis R. Rodriguez return 0; 268db86f07eSLuis R. Rodriguez } 269db86f07eSLuis R. Rodriguez module_init(ath9k_cmn_init); 270db86f07eSLuis R. Rodriguez 271db86f07eSLuis R. Rodriguez static void __exit ath9k_cmn_exit(void) 272db86f07eSLuis R. Rodriguez { 273db86f07eSLuis R. Rodriguez return; 274db86f07eSLuis R. Rodriguez } 275db86f07eSLuis R. Rodriguez module_exit(ath9k_cmn_exit); 276