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 306438696eSOleksij Rempel /* Assumes you've already done the endian to CPU conversion */ 316438696eSOleksij Rempel bool ath9k_cmn_rx_accept(struct ath_common *common, 326438696eSOleksij Rempel struct ieee80211_hdr *hdr, 336438696eSOleksij Rempel struct ieee80211_rx_status *rxs, 346438696eSOleksij Rempel struct ath_rx_status *rx_stats, 356438696eSOleksij Rempel bool *decrypt_error, 366438696eSOleksij Rempel unsigned int rxfilter) 376438696eSOleksij Rempel { 386438696eSOleksij Rempel struct ath_hw *ah = common->ah; 396438696eSOleksij Rempel bool is_mc, is_valid_tkip, strip_mic, mic_error; 406438696eSOleksij Rempel __le16 fc; 416438696eSOleksij Rempel 426438696eSOleksij Rempel fc = hdr->frame_control; 436438696eSOleksij Rempel 446438696eSOleksij Rempel is_mc = !!is_multicast_ether_addr(hdr->addr1); 456438696eSOleksij Rempel is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && 466438696eSOleksij Rempel test_bit(rx_stats->rs_keyix, common->tkip_keymap); 476438696eSOleksij Rempel strip_mic = is_valid_tkip && ieee80211_is_data(fc) && 486438696eSOleksij Rempel ieee80211_has_protected(fc) && 496438696eSOleksij Rempel !(rx_stats->rs_status & 506438696eSOleksij Rempel (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | 516438696eSOleksij Rempel ATH9K_RXERR_KEYMISS)); 526438696eSOleksij Rempel 536438696eSOleksij Rempel /* 546438696eSOleksij Rempel * Key miss events are only relevant for pairwise keys where the 556438696eSOleksij Rempel * descriptor does contain a valid key index. This has been observed 566438696eSOleksij Rempel * mostly with CCMP encryption. 576438696eSOleksij Rempel */ 586438696eSOleksij Rempel if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || 596438696eSOleksij Rempel !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) 606438696eSOleksij Rempel rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; 616438696eSOleksij Rempel 626438696eSOleksij Rempel mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && 636438696eSOleksij Rempel !ieee80211_has_morefrags(fc) && 646438696eSOleksij Rempel !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && 656438696eSOleksij Rempel (rx_stats->rs_status & ATH9K_RXERR_MIC); 666438696eSOleksij Rempel 676438696eSOleksij Rempel /* 686438696eSOleksij Rempel * The rx_stats->rs_status will not be set until the end of the 696438696eSOleksij Rempel * chained descriptors so it can be ignored if rs_more is set. The 706438696eSOleksij Rempel * rs_more will be false at the last element of the chained 716438696eSOleksij Rempel * descriptors. 726438696eSOleksij Rempel */ 736438696eSOleksij Rempel if (rx_stats->rs_status != 0) { 746438696eSOleksij Rempel u8 status_mask; 756438696eSOleksij Rempel 766438696eSOleksij Rempel if (rx_stats->rs_status & ATH9K_RXERR_CRC) { 776438696eSOleksij Rempel rxs->flag |= RX_FLAG_FAILED_FCS_CRC; 786438696eSOleksij Rempel mic_error = false; 796438696eSOleksij Rempel } 806438696eSOleksij Rempel 816438696eSOleksij Rempel if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || 826438696eSOleksij Rempel (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { 836438696eSOleksij Rempel *decrypt_error = true; 846438696eSOleksij Rempel mic_error = false; 856438696eSOleksij Rempel } 866438696eSOleksij Rempel 876438696eSOleksij Rempel 886438696eSOleksij Rempel /* 896438696eSOleksij Rempel * Reject error frames with the exception of 906438696eSOleksij Rempel * decryption and MIC failures. For monitor mode, 916438696eSOleksij Rempel * we also ignore the CRC error. 926438696eSOleksij Rempel */ 936438696eSOleksij Rempel status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | 946438696eSOleksij Rempel ATH9K_RXERR_KEYMISS; 956438696eSOleksij Rempel 966438696eSOleksij Rempel if (ah->is_monitoring && (rxfilter & FIF_FCSFAIL)) 976438696eSOleksij Rempel status_mask |= ATH9K_RXERR_CRC; 986438696eSOleksij Rempel 996438696eSOleksij Rempel if (rx_stats->rs_status & ~status_mask) 1006438696eSOleksij Rempel return false; 1016438696eSOleksij Rempel } 1026438696eSOleksij Rempel 1036438696eSOleksij Rempel /* 1046438696eSOleksij Rempel * For unicast frames the MIC error bit can have false positives, 1056438696eSOleksij Rempel * so all MIC error reports need to be validated in software. 1066438696eSOleksij Rempel * False negatives are not common, so skip software verification 1076438696eSOleksij Rempel * if the hardware considers the MIC valid. 1086438696eSOleksij Rempel */ 1096438696eSOleksij Rempel if (strip_mic) 1106438696eSOleksij Rempel rxs->flag |= RX_FLAG_MMIC_STRIPPED; 1116438696eSOleksij Rempel else if (is_mc && mic_error) 1126438696eSOleksij Rempel rxs->flag |= RX_FLAG_MMIC_ERROR; 1136438696eSOleksij Rempel 1146438696eSOleksij Rempel return true; 1156438696eSOleksij Rempel } 1166438696eSOleksij Rempel EXPORT_SYMBOL(ath9k_cmn_rx_accept); 1176438696eSOleksij Rempel 1185a078fcbSOleksij Rempel void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, 1195a078fcbSOleksij Rempel struct sk_buff *skb, 1205a078fcbSOleksij Rempel struct ath_rx_status *rx_stats, 1215a078fcbSOleksij Rempel struct ieee80211_rx_status *rxs, 1225a078fcbSOleksij Rempel bool decrypt_error) 1235a078fcbSOleksij Rempel { 1245a078fcbSOleksij Rempel struct ath_hw *ah = common->ah; 1255a078fcbSOleksij Rempel struct ieee80211_hdr *hdr; 1265a078fcbSOleksij Rempel int hdrlen, padpos, padsize; 1275a078fcbSOleksij Rempel u8 keyix; 1285a078fcbSOleksij Rempel __le16 fc; 1295a078fcbSOleksij Rempel 1305a078fcbSOleksij Rempel /* see if any padding is done by the hw and remove it */ 1315a078fcbSOleksij Rempel hdr = (struct ieee80211_hdr *) skb->data; 1325a078fcbSOleksij Rempel hdrlen = ieee80211_get_hdrlen_from_skb(skb); 1335a078fcbSOleksij Rempel fc = hdr->frame_control; 1345a078fcbSOleksij Rempel padpos = ieee80211_hdrlen(fc); 1355a078fcbSOleksij Rempel 1365a078fcbSOleksij Rempel /* The MAC header is padded to have 32-bit boundary if the 1375a078fcbSOleksij Rempel * packet payload is non-zero. The general calculation for 1385a078fcbSOleksij Rempel * padsize would take into account odd header lengths: 1395a078fcbSOleksij Rempel * padsize = (4 - padpos % 4) % 4; However, since only 1405a078fcbSOleksij Rempel * even-length headers are used, padding can only be 0 or 2 1415a078fcbSOleksij Rempel * bytes and we can optimize this a bit. In addition, we must 1425a078fcbSOleksij Rempel * not try to remove padding from short control frames that do 1435a078fcbSOleksij Rempel * not have payload. */ 1445a078fcbSOleksij Rempel padsize = padpos & 3; 1455a078fcbSOleksij Rempel if (padsize && skb->len>=padpos+padsize+FCS_LEN) { 1465a078fcbSOleksij Rempel memmove(skb->data + padsize, skb->data, padpos); 1475a078fcbSOleksij Rempel skb_pull(skb, padsize); 1485a078fcbSOleksij Rempel } 1495a078fcbSOleksij Rempel 1505a078fcbSOleksij Rempel keyix = rx_stats->rs_keyix; 1515a078fcbSOleksij Rempel 1525a078fcbSOleksij Rempel if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && 1535a078fcbSOleksij Rempel ieee80211_has_protected(fc)) { 1545a078fcbSOleksij Rempel rxs->flag |= RX_FLAG_DECRYPTED; 1555a078fcbSOleksij Rempel } else if (ieee80211_has_protected(fc) 1565a078fcbSOleksij Rempel && !decrypt_error && skb->len >= hdrlen + 4) { 1575a078fcbSOleksij Rempel keyix = skb->data[hdrlen + 3] >> 6; 1585a078fcbSOleksij Rempel 1595a078fcbSOleksij Rempel if (test_bit(keyix, common->keymap)) 1605a078fcbSOleksij Rempel rxs->flag |= RX_FLAG_DECRYPTED; 1615a078fcbSOleksij Rempel } 162e6510b11SChun-Yeow Yeoh if (ah->sw_mgmt_crypto_rx && 1635a078fcbSOleksij Rempel (rxs->flag & RX_FLAG_DECRYPTED) && 1645a078fcbSOleksij Rempel ieee80211_is_mgmt(fc)) 1655a078fcbSOleksij Rempel /* Use software decrypt for management frames. */ 1665a078fcbSOleksij Rempel rxs->flag &= ~RX_FLAG_DECRYPTED; 1675a078fcbSOleksij Rempel } 1685a078fcbSOleksij Rempel EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess); 1695a078fcbSOleksij Rempel 17012746036SOleksij Rempel int ath9k_cmn_process_rate(struct ath_common *common, 17112746036SOleksij Rempel struct ieee80211_hw *hw, 17212746036SOleksij Rempel struct ath_rx_status *rx_stats, 17312746036SOleksij Rempel struct ieee80211_rx_status *rxs) 17412746036SOleksij Rempel { 17512746036SOleksij Rempel struct ieee80211_supported_band *sband; 17657fbcce3SJohannes Berg enum nl80211_band band; 17712746036SOleksij Rempel unsigned int i = 0; 17812746036SOleksij Rempel struct ath_hw *ah = common->ah; 17912746036SOleksij Rempel 18012746036SOleksij Rempel band = ah->curchan->chan->band; 18112746036SOleksij Rempel sband = hw->wiphy->bands[band]; 18212746036SOleksij Rempel 18312746036SOleksij Rempel if (IS_CHAN_QUARTER_RATE(ah->curchan)) 184*7fdd69c5SJohannes Berg rxs->enc_flags |= RX_ENC_FLAG_5MHZ; 18512746036SOleksij Rempel else if (IS_CHAN_HALF_RATE(ah->curchan)) 186*7fdd69c5SJohannes Berg rxs->enc_flags |= RX_ENC_FLAG_10MHZ; 18712746036SOleksij Rempel 18812746036SOleksij Rempel if (rx_stats->rs_rate & 0x80) { 18912746036SOleksij Rempel /* HT rate */ 190*7fdd69c5SJohannes Berg rxs->enc_flags |= RX_ENC_FLAG_HT | rx_stats->enc_flags; 19112746036SOleksij Rempel rxs->rate_idx = rx_stats->rs_rate & 0x7f; 19212746036SOleksij Rempel return 0; 19312746036SOleksij Rempel } 19412746036SOleksij Rempel 19512746036SOleksij Rempel for (i = 0; i < sband->n_bitrates; i++) { 19612746036SOleksij Rempel if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { 19712746036SOleksij Rempel rxs->rate_idx = i; 19812746036SOleksij Rempel return 0; 19912746036SOleksij Rempel } 20012746036SOleksij Rempel if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { 201*7fdd69c5SJohannes Berg rxs->enc_flags |= RX_ENC_FLAG_SHORTPRE; 20212746036SOleksij Rempel rxs->rate_idx = i; 20312746036SOleksij Rempel return 0; 20412746036SOleksij Rempel } 20512746036SOleksij Rempel } 20612746036SOleksij Rempel 20712746036SOleksij Rempel return -EINVAL; 20812746036SOleksij Rempel } 20912746036SOleksij Rempel EXPORT_SYMBOL(ath9k_cmn_process_rate); 21012746036SOleksij Rempel 21132efb0ccSOleksij Rempel void ath9k_cmn_process_rssi(struct ath_common *common, 21232efb0ccSOleksij Rempel struct ieee80211_hw *hw, 21332efb0ccSOleksij Rempel struct ath_rx_status *rx_stats, 21432efb0ccSOleksij Rempel struct ieee80211_rx_status *rxs) 21532efb0ccSOleksij Rempel { 21632efb0ccSOleksij Rempel struct ath_hw *ah = common->ah; 21732efb0ccSOleksij Rempel int last_rssi; 21832efb0ccSOleksij Rempel int rssi = rx_stats->rs_rssi; 21932efb0ccSOleksij Rempel int i, j; 22032efb0ccSOleksij Rempel 22132efb0ccSOleksij Rempel /* 22232efb0ccSOleksij Rempel * RSSI is not available for subframes in an A-MPDU. 22332efb0ccSOleksij Rempel */ 22432efb0ccSOleksij Rempel if (rx_stats->rs_moreaggr) { 22532efb0ccSOleksij Rempel rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; 22632efb0ccSOleksij Rempel return; 22732efb0ccSOleksij Rempel } 22832efb0ccSOleksij Rempel 22932efb0ccSOleksij Rempel /* 23032efb0ccSOleksij Rempel * Check if the RSSI for the last subframe in an A-MPDU 23132efb0ccSOleksij Rempel * or an unaggregated frame is valid. 23232efb0ccSOleksij Rempel */ 23332efb0ccSOleksij Rempel if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) { 23432efb0ccSOleksij Rempel rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; 23532efb0ccSOleksij Rempel return; 23632efb0ccSOleksij Rempel } 23732efb0ccSOleksij Rempel 23832efb0ccSOleksij Rempel for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) { 23932efb0ccSOleksij Rempel s8 rssi; 24032efb0ccSOleksij Rempel 24132efb0ccSOleksij Rempel if (!(ah->rxchainmask & BIT(i))) 24232efb0ccSOleksij Rempel continue; 24332efb0ccSOleksij Rempel 24432efb0ccSOleksij Rempel rssi = rx_stats->rs_rssi_ctl[i]; 24532efb0ccSOleksij Rempel if (rssi != ATH9K_RSSI_BAD) { 24632efb0ccSOleksij Rempel rxs->chains |= BIT(j); 24732efb0ccSOleksij Rempel rxs->chain_signal[j] = ah->noise + rssi; 24832efb0ccSOleksij Rempel } 24932efb0ccSOleksij Rempel j++; 25032efb0ccSOleksij Rempel } 25132efb0ccSOleksij Rempel 25232efb0ccSOleksij Rempel /* 25332efb0ccSOleksij Rempel * Update Beacon RSSI, this is used by ANI. 25432efb0ccSOleksij Rempel */ 25532efb0ccSOleksij Rempel if (rx_stats->is_mybeacon && 25632efb0ccSOleksij Rempel ((ah->opmode == NL80211_IFTYPE_STATION) || 25732efb0ccSOleksij Rempel (ah->opmode == NL80211_IFTYPE_ADHOC))) { 25832efb0ccSOleksij Rempel ATH_RSSI_LPF(common->last_rssi, rx_stats->rs_rssi); 25932efb0ccSOleksij Rempel last_rssi = common->last_rssi; 26032efb0ccSOleksij Rempel 26132efb0ccSOleksij Rempel if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) 26232efb0ccSOleksij Rempel rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); 26332efb0ccSOleksij Rempel if (rssi < 0) 26432efb0ccSOleksij Rempel rssi = 0; 26532efb0ccSOleksij Rempel 26632efb0ccSOleksij Rempel ah->stats.avgbrssi = rssi; 26732efb0ccSOleksij Rempel } 26832efb0ccSOleksij Rempel 26932efb0ccSOleksij Rempel rxs->signal = ah->noise + rx_stats->rs_rssi; 27032efb0ccSOleksij Rempel } 27132efb0ccSOleksij Rempel EXPORT_SYMBOL(ath9k_cmn_process_rssi); 27232efb0ccSOleksij Rempel 273fb9987d0SSujith int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) 274fb9987d0SSujith { 275fb9987d0SSujith struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 276fb9987d0SSujith 277fb9987d0SSujith if (tx_info->control.hw_key) { 27897359d12SJohannes Berg switch (tx_info->control.hw_key->cipher) { 27997359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP40: 28097359d12SJohannes Berg case WLAN_CIPHER_SUITE_WEP104: 281fb9987d0SSujith return ATH9K_KEY_TYPE_WEP; 28297359d12SJohannes Berg case WLAN_CIPHER_SUITE_TKIP: 283fb9987d0SSujith return ATH9K_KEY_TYPE_TKIP; 28497359d12SJohannes Berg case WLAN_CIPHER_SUITE_CCMP: 285fb9987d0SSujith return ATH9K_KEY_TYPE_AES; 28697359d12SJohannes Berg default: 28797359d12SJohannes Berg break; 28897359d12SJohannes Berg } 289fb9987d0SSujith } 290fb9987d0SSujith 291fb9987d0SSujith return ATH9K_KEY_TYPE_CLEAR; 292fb9987d0SSujith } 293fb9987d0SSujith EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype); 294fb9987d0SSujith 295fb9987d0SSujith /* 296fb9987d0SSujith * Update internal channel flags. 297fb9987d0SSujith */ 2982297f1c7SFelix Fietkau static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, 2990671894fSSimon Wunderlich struct cfg80211_chan_def *chandef) 300fb9987d0SSujith { 3016b21fd20SFelix Fietkau struct ieee80211_channel *chan = chandef->chan; 3026b21fd20SFelix Fietkau u16 flags = 0; 303fb9987d0SSujith 3046b21fd20SFelix Fietkau ichan->channel = chan->center_freq; 3056b21fd20SFelix Fietkau ichan->chan = chan; 3066b21fd20SFelix Fietkau 30757fbcce3SJohannes Berg if (chan->band == NL80211_BAND_5GHZ) 3086b21fd20SFelix Fietkau flags |= CHANNEL_5GHZ; 309fb9987d0SSujith 3100671894fSSimon Wunderlich switch (chandef->width) { 3110671894fSSimon Wunderlich case NL80211_CHAN_WIDTH_5: 3126b21fd20SFelix Fietkau flags |= CHANNEL_QUARTER; 3130671894fSSimon Wunderlich break; 3140671894fSSimon Wunderlich case NL80211_CHAN_WIDTH_10: 3156b21fd20SFelix Fietkau flags |= CHANNEL_HALF; 3160671894fSSimon Wunderlich break; 3170671894fSSimon Wunderlich case NL80211_CHAN_WIDTH_20_NOHT: 3180671894fSSimon Wunderlich break; 3190671894fSSimon Wunderlich case NL80211_CHAN_WIDTH_20: 3206b21fd20SFelix Fietkau flags |= CHANNEL_HT; 3216b21fd20SFelix Fietkau break; 3220671894fSSimon Wunderlich case NL80211_CHAN_WIDTH_40: 3236b21fd20SFelix Fietkau if (chandef->center_freq1 > chandef->chan->center_freq) 3246b21fd20SFelix Fietkau flags |= CHANNEL_HT40PLUS | CHANNEL_HT; 3256b21fd20SFelix Fietkau else 3266b21fd20SFelix Fietkau flags |= CHANNEL_HT40MINUS | CHANNEL_HT; 3270671894fSSimon Wunderlich break; 3280671894fSSimon Wunderlich default: 3290671894fSSimon Wunderlich WARN_ON(1); 3300671894fSSimon Wunderlich } 3316b21fd20SFelix Fietkau 3326b21fd20SFelix Fietkau ichan->channelFlags = flags; 333fb9987d0SSujith } 334fb9987d0SSujith 335fb9987d0SSujith /* 336fb9987d0SSujith * Get the internal channel reference. 337fb9987d0SSujith */ 3382297f1c7SFelix Fietkau struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw, 3392297f1c7SFelix Fietkau struct ath_hw *ah, 3402297f1c7SFelix Fietkau struct cfg80211_chan_def *chandef) 341fb9987d0SSujith { 3422297f1c7SFelix Fietkau struct ieee80211_channel *curchan = chandef->chan; 343fb9987d0SSujith struct ath9k_channel *channel; 344fb9987d0SSujith 345f40c4608SFelix Fietkau channel = &ah->channels[curchan->hw_value]; 3462297f1c7SFelix Fietkau ath9k_cmn_update_ichannel(channel, chandef); 347fb9987d0SSujith 348fb9987d0SSujith return channel; 349fb9987d0SSujith } 3502297f1c7SFelix Fietkau EXPORT_SYMBOL(ath9k_cmn_get_channel); 351fb9987d0SSujith 35261389f3eSSujith int ath9k_cmn_count_streams(unsigned int chainmask, int max) 35361389f3eSSujith { 35461389f3eSSujith int streams = 0; 35561389f3eSSujith 35661389f3eSSujith do { 35761389f3eSSujith if (++streams == max) 35861389f3eSSujith break; 35961389f3eSSujith } while ((chainmask = chainmask & (chainmask - 1))); 36061389f3eSSujith 36161389f3eSSujith return streams; 36261389f3eSSujith } 36361389f3eSSujith EXPORT_SYMBOL(ath9k_cmn_count_streams); 36461389f3eSSujith 3655048e8c3SRajkumar Manoharan void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, 3665048e8c3SRajkumar Manoharan u16 new_txpow, u16 *txpower) 3675048e8c3SRajkumar Manoharan { 368ca2c68ccSFelix Fietkau struct ath_regulatory *reg = ath9k_hw_regulatory(ah); 369ca2c68ccSFelix Fietkau 37076325451SFelix Fietkau if (reg->power_limit != new_txpow) 3715048e8c3SRajkumar Manoharan ath9k_hw_set_txpowerlimit(ah, new_txpow, false); 37276325451SFelix Fietkau 3735048e8c3SRajkumar Manoharan /* read back in case value is clamped */ 374ca2c68ccSFelix Fietkau *txpower = reg->max_power_level; 3755048e8c3SRajkumar Manoharan } 3765048e8c3SRajkumar Manoharan EXPORT_SYMBOL(ath9k_cmn_update_txpow); 3775048e8c3SRajkumar Manoharan 378f82b4bdeSRajkumar Manoharan void ath9k_cmn_init_crypto(struct ath_hw *ah) 379f82b4bdeSRajkumar Manoharan { 380f82b4bdeSRajkumar Manoharan struct ath_common *common = ath9k_hw_common(ah); 381f82b4bdeSRajkumar Manoharan int i = 0; 382f82b4bdeSRajkumar Manoharan 383f82b4bdeSRajkumar Manoharan /* Get the hardware key cache size. */ 384f82b4bdeSRajkumar Manoharan common->keymax = AR_KEYTABLE_SIZE; 385f82b4bdeSRajkumar Manoharan 386f82b4bdeSRajkumar Manoharan /* 387f82b4bdeSRajkumar Manoharan * Check whether the separate key cache entries 388f82b4bdeSRajkumar Manoharan * are required to handle both tx+rx MIC keys. 389f82b4bdeSRajkumar Manoharan * With split mic keys the number of stations is limited 390f82b4bdeSRajkumar Manoharan * to 27 otherwise 59. 391f82b4bdeSRajkumar Manoharan */ 392f82b4bdeSRajkumar Manoharan if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) 393f82b4bdeSRajkumar Manoharan common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; 394f82b4bdeSRajkumar Manoharan 395f82b4bdeSRajkumar Manoharan /* 396f82b4bdeSRajkumar Manoharan * Reset the key cache since some parts do not 397f82b4bdeSRajkumar Manoharan * reset the contents on initial power up. 398f82b4bdeSRajkumar Manoharan */ 399f82b4bdeSRajkumar Manoharan for (i = 0; i < common->keymax; i++) 400f82b4bdeSRajkumar Manoharan ath_hw_keyreset(common, (u16) i); 401f82b4bdeSRajkumar Manoharan } 402f82b4bdeSRajkumar Manoharan EXPORT_SYMBOL(ath9k_cmn_init_crypto); 403f82b4bdeSRajkumar Manoharan 404db86f07eSLuis R. Rodriguez static int __init ath9k_cmn_init(void) 405db86f07eSLuis R. Rodriguez { 406db86f07eSLuis R. Rodriguez return 0; 407db86f07eSLuis R. Rodriguez } 408db86f07eSLuis R. Rodriguez module_init(ath9k_cmn_init); 409db86f07eSLuis R. Rodriguez 410db86f07eSLuis R. Rodriguez static void __exit ath9k_cmn_exit(void) 411db86f07eSLuis R. Rodriguez { 412db86f07eSLuis R. Rodriguez return; 413db86f07eSLuis R. Rodriguez } 414db86f07eSLuis R. Rodriguez module_exit(ath9k_cmn_exit); 415