xref: /linux/drivers/net/wireless/ath/ath9k/common.c (revision c25141062a82ae8bddced1b3ce2b57a1c0efabe0)
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 */
ath9k_cmn_rx_accept(struct ath_common * common,struct ieee80211_hdr * hdr,struct ieee80211_rx_status * rxs,struct ath_rx_status * rx_stats,bool * decrypt_error,unsigned int rxfilter)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 
ath9k_cmn_rx_skb_postprocess(struct ath_common * common,struct sk_buff * skb,struct ath_rx_status * rx_stats,struct ieee80211_rx_status * rxs,bool decrypt_error)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 
ath9k_cmn_process_rate(struct ath_common * common,struct ieee80211_hw * hw,struct ath_rx_status * rx_stats,struct ieee80211_rx_status * rxs)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))
184da6a4352SJohannes Berg 		rxs->bw = RATE_INFO_BW_5;
18512746036SOleksij Rempel 	else if (IS_CHAN_HALF_RATE(ah->curchan))
186da6a4352SJohannes Berg 		rxs->bw = RATE_INFO_BW_10;
18712746036SOleksij Rempel 
18812746036SOleksij Rempel 	if (rx_stats->rs_rate & 0x80) {
18912746036SOleksij Rempel 		/* HT rate */
190da6a4352SJohannes Berg 		rxs->encoding = RX_ENC_HT;
191da6a4352SJohannes Berg 		rxs->enc_flags |= rx_stats->enc_flags;
192da6a4352SJohannes Berg 		rxs->bw = rx_stats->bw;
19312746036SOleksij Rempel 		rxs->rate_idx = rx_stats->rs_rate & 0x7f;
19412746036SOleksij Rempel 		return 0;
19512746036SOleksij Rempel 	}
19612746036SOleksij Rempel 
19712746036SOleksij Rempel 	for (i = 0; i < sband->n_bitrates; i++) {
19812746036SOleksij Rempel 		if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
19912746036SOleksij Rempel 			rxs->rate_idx = i;
20012746036SOleksij Rempel 			return 0;
20112746036SOleksij Rempel 		}
20212746036SOleksij Rempel 		if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
2037fdd69c5SJohannes Berg 			rxs->enc_flags |= RX_ENC_FLAG_SHORTPRE;
20412746036SOleksij Rempel 			rxs->rate_idx = i;
20512746036SOleksij Rempel 			return 0;
20612746036SOleksij Rempel 		}
20712746036SOleksij Rempel 	}
20812746036SOleksij Rempel 
20912746036SOleksij Rempel 	return -EINVAL;
21012746036SOleksij Rempel }
21112746036SOleksij Rempel EXPORT_SYMBOL(ath9k_cmn_process_rate);
21212746036SOleksij Rempel 
ath9k_cmn_process_rssi(struct ath_common * common,struct ieee80211_hw * hw,struct ath_rx_status * rx_stats,struct ieee80211_rx_status * rxs)21332efb0ccSOleksij Rempel void ath9k_cmn_process_rssi(struct ath_common *common,
21432efb0ccSOleksij Rempel 			    struct ieee80211_hw *hw,
21532efb0ccSOleksij Rempel 			    struct ath_rx_status *rx_stats,
21632efb0ccSOleksij Rempel 			    struct ieee80211_rx_status *rxs)
21732efb0ccSOleksij Rempel {
21832efb0ccSOleksij Rempel 	struct ath_hw *ah = common->ah;
21932efb0ccSOleksij Rempel 	int last_rssi;
22032efb0ccSOleksij Rempel 	int rssi = rx_stats->rs_rssi;
22132efb0ccSOleksij Rempel 	int i, j;
22232efb0ccSOleksij Rempel 
22332efb0ccSOleksij Rempel 	/*
22432efb0ccSOleksij Rempel 	 * RSSI is not available for subframes in an A-MPDU.
22532efb0ccSOleksij Rempel 	 */
22632efb0ccSOleksij Rempel 	if (rx_stats->rs_moreaggr) {
22732efb0ccSOleksij Rempel 		rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
22832efb0ccSOleksij Rempel 		return;
22932efb0ccSOleksij Rempel 	}
23032efb0ccSOleksij Rempel 
23132efb0ccSOleksij Rempel 	/*
23232efb0ccSOleksij Rempel 	 * Check if the RSSI for the last subframe in an A-MPDU
23332efb0ccSOleksij Rempel 	 * or an unaggregated frame is valid.
23432efb0ccSOleksij Rempel 	 */
23532efb0ccSOleksij Rempel 	if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) {
23632efb0ccSOleksij Rempel 		rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
23732efb0ccSOleksij Rempel 		return;
23832efb0ccSOleksij Rempel 	}
23932efb0ccSOleksij Rempel 
24032efb0ccSOleksij Rempel 	for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) {
24132efb0ccSOleksij Rempel 		s8 rssi;
24232efb0ccSOleksij Rempel 
24332efb0ccSOleksij Rempel 		if (!(ah->rxchainmask & BIT(i)))
24432efb0ccSOleksij Rempel 			continue;
24532efb0ccSOleksij Rempel 
24632efb0ccSOleksij Rempel 		rssi = rx_stats->rs_rssi_ctl[i];
24732efb0ccSOleksij Rempel 		if (rssi != ATH9K_RSSI_BAD) {
24832efb0ccSOleksij Rempel 		    rxs->chains |= BIT(j);
24932efb0ccSOleksij Rempel 		    rxs->chain_signal[j] = ah->noise + rssi;
25032efb0ccSOleksij Rempel 		}
25132efb0ccSOleksij Rempel 		j++;
25232efb0ccSOleksij Rempel 	}
25332efb0ccSOleksij Rempel 
25432efb0ccSOleksij Rempel 	/*
25532efb0ccSOleksij Rempel 	 * Update Beacon RSSI, this is used by ANI.
25632efb0ccSOleksij Rempel 	 */
25732efb0ccSOleksij Rempel 	if (rx_stats->is_mybeacon &&
25832efb0ccSOleksij Rempel 	    ((ah->opmode == NL80211_IFTYPE_STATION) ||
25932efb0ccSOleksij Rempel 	     (ah->opmode == NL80211_IFTYPE_ADHOC))) {
26032efb0ccSOleksij Rempel 		ATH_RSSI_LPF(common->last_rssi, rx_stats->rs_rssi);
26132efb0ccSOleksij Rempel 		last_rssi = common->last_rssi;
26232efb0ccSOleksij Rempel 
26332efb0ccSOleksij Rempel 		if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
26432efb0ccSOleksij Rempel 			rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
26532efb0ccSOleksij Rempel 		if (rssi < 0)
26632efb0ccSOleksij Rempel 			rssi = 0;
26732efb0ccSOleksij Rempel 
26832efb0ccSOleksij Rempel 		ah->stats.avgbrssi = rssi;
26932efb0ccSOleksij Rempel 	}
27032efb0ccSOleksij Rempel 
27132efb0ccSOleksij Rempel 	rxs->signal = ah->noise + rx_stats->rs_rssi;
27232efb0ccSOleksij Rempel }
27332efb0ccSOleksij Rempel EXPORT_SYMBOL(ath9k_cmn_process_rssi);
27432efb0ccSOleksij Rempel 
ath9k_cmn_get_hw_crypto_keytype(struct sk_buff * skb)275fb9987d0SSujith int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)
276fb9987d0SSujith {
277fb9987d0SSujith 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
278fb9987d0SSujith 
279fb9987d0SSujith 	if (tx_info->control.hw_key) {
28097359d12SJohannes Berg 		switch (tx_info->control.hw_key->cipher) {
28197359d12SJohannes Berg 		case WLAN_CIPHER_SUITE_WEP40:
28297359d12SJohannes Berg 		case WLAN_CIPHER_SUITE_WEP104:
283fb9987d0SSujith 			return ATH9K_KEY_TYPE_WEP;
28497359d12SJohannes Berg 		case WLAN_CIPHER_SUITE_TKIP:
285fb9987d0SSujith 			return ATH9K_KEY_TYPE_TKIP;
28697359d12SJohannes Berg 		case WLAN_CIPHER_SUITE_CCMP:
287fb9987d0SSujith 			return ATH9K_KEY_TYPE_AES;
28897359d12SJohannes Berg 		default:
28997359d12SJohannes Berg 			break;
29097359d12SJohannes Berg 		}
291fb9987d0SSujith 	}
292fb9987d0SSujith 
293fb9987d0SSujith 	return ATH9K_KEY_TYPE_CLEAR;
294fb9987d0SSujith }
295fb9987d0SSujith EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype);
296fb9987d0SSujith 
297fb9987d0SSujith /*
298fb9987d0SSujith  * Update internal channel flags.
299fb9987d0SSujith  */
ath9k_cmn_update_ichannel(struct ath9k_channel * ichan,struct cfg80211_chan_def * chandef)3002297f1c7SFelix Fietkau static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
3010671894fSSimon Wunderlich 				      struct cfg80211_chan_def *chandef)
302fb9987d0SSujith {
3036b21fd20SFelix Fietkau 	struct ieee80211_channel *chan = chandef->chan;
3046b21fd20SFelix Fietkau 	u16 flags = 0;
305fb9987d0SSujith 
3066b21fd20SFelix Fietkau 	ichan->channel = chan->center_freq;
3076b21fd20SFelix Fietkau 	ichan->chan = chan;
3086b21fd20SFelix Fietkau 
30957fbcce3SJohannes Berg 	if (chan->band == NL80211_BAND_5GHZ)
3106b21fd20SFelix Fietkau 		flags |= CHANNEL_5GHZ;
311fb9987d0SSujith 
3120671894fSSimon Wunderlich 	switch (chandef->width) {
3130671894fSSimon Wunderlich 	case NL80211_CHAN_WIDTH_5:
3146b21fd20SFelix Fietkau 		flags |= CHANNEL_QUARTER;
3150671894fSSimon Wunderlich 		break;
3160671894fSSimon Wunderlich 	case NL80211_CHAN_WIDTH_10:
3176b21fd20SFelix Fietkau 		flags |= CHANNEL_HALF;
3180671894fSSimon Wunderlich 		break;
3190671894fSSimon Wunderlich 	case NL80211_CHAN_WIDTH_20_NOHT:
3200671894fSSimon Wunderlich 		break;
3210671894fSSimon Wunderlich 	case NL80211_CHAN_WIDTH_20:
3226b21fd20SFelix Fietkau 		flags |= CHANNEL_HT;
3236b21fd20SFelix Fietkau 		break;
3240671894fSSimon Wunderlich 	case NL80211_CHAN_WIDTH_40:
3256b21fd20SFelix Fietkau 		if (chandef->center_freq1 > chandef->chan->center_freq)
3266b21fd20SFelix Fietkau 			flags |= CHANNEL_HT40PLUS | CHANNEL_HT;
3276b21fd20SFelix Fietkau 		else
3286b21fd20SFelix Fietkau 			flags |= CHANNEL_HT40MINUS | CHANNEL_HT;
3290671894fSSimon Wunderlich 		break;
3300671894fSSimon Wunderlich 	default:
3310671894fSSimon Wunderlich 		WARN_ON(1);
3320671894fSSimon Wunderlich 	}
3336b21fd20SFelix Fietkau 
3346b21fd20SFelix Fietkau 	ichan->channelFlags = flags;
335fb9987d0SSujith }
336fb9987d0SSujith 
337fb9987d0SSujith /*
338fb9987d0SSujith  * Get the internal channel reference.
339fb9987d0SSujith  */
ath9k_cmn_get_channel(struct ieee80211_hw * hw,struct ath_hw * ah,struct cfg80211_chan_def * chandef)3402297f1c7SFelix Fietkau struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw,
3412297f1c7SFelix Fietkau 					    struct ath_hw *ah,
3422297f1c7SFelix Fietkau 					    struct cfg80211_chan_def *chandef)
343fb9987d0SSujith {
3442297f1c7SFelix Fietkau 	struct ieee80211_channel *curchan = chandef->chan;
345fb9987d0SSujith 	struct ath9k_channel *channel;
346fb9987d0SSujith 
347f40c4608SFelix Fietkau 	channel = &ah->channels[curchan->hw_value];
3482297f1c7SFelix Fietkau 	ath9k_cmn_update_ichannel(channel, chandef);
349fb9987d0SSujith 
350fb9987d0SSujith 	return channel;
351fb9987d0SSujith }
3522297f1c7SFelix Fietkau EXPORT_SYMBOL(ath9k_cmn_get_channel);
353fb9987d0SSujith 
ath9k_cmn_count_streams(unsigned int chainmask,int max)35461389f3eSSujith int ath9k_cmn_count_streams(unsigned int chainmask, int max)
35561389f3eSSujith {
35661389f3eSSujith 	int streams = 0;
35761389f3eSSujith 
35861389f3eSSujith 	do {
35961389f3eSSujith 		if (++streams == max)
36061389f3eSSujith 			break;
36161389f3eSSujith 	} while ((chainmask = chainmask & (chainmask - 1)));
36261389f3eSSujith 
36361389f3eSSujith 	return streams;
36461389f3eSSujith }
36561389f3eSSujith EXPORT_SYMBOL(ath9k_cmn_count_streams);
36661389f3eSSujith 
ath9k_cmn_update_txpow(struct ath_hw * ah,u16 cur_txpow,u16 new_txpow,u16 * txpower)3675048e8c3SRajkumar Manoharan void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
3685048e8c3SRajkumar Manoharan 			    u16 new_txpow, u16 *txpower)
3695048e8c3SRajkumar Manoharan {
370ca2c68ccSFelix Fietkau 	struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
371ca2c68ccSFelix Fietkau 
372*b01c9e32SStanislaw Gruszka 	if (ah->curchan && reg->power_limit != new_txpow)
3735048e8c3SRajkumar Manoharan 		ath9k_hw_set_txpowerlimit(ah, new_txpow, false);
37476325451SFelix Fietkau 
3755048e8c3SRajkumar Manoharan 	/* read back in case value is clamped */
376ca2c68ccSFelix Fietkau 	*txpower = reg->max_power_level;
3775048e8c3SRajkumar Manoharan }
3785048e8c3SRajkumar Manoharan EXPORT_SYMBOL(ath9k_cmn_update_txpow);
3795048e8c3SRajkumar Manoharan 
ath9k_cmn_init_crypto(struct ath_hw * ah)380f82b4bdeSRajkumar Manoharan void ath9k_cmn_init_crypto(struct ath_hw *ah)
381f82b4bdeSRajkumar Manoharan {
382f82b4bdeSRajkumar Manoharan 	struct ath_common *common = ath9k_hw_common(ah);
383f82b4bdeSRajkumar Manoharan 	int i = 0;
384f82b4bdeSRajkumar Manoharan 
385f82b4bdeSRajkumar Manoharan 	/* Get the hardware key cache size. */
386f82b4bdeSRajkumar Manoharan 	common->keymax = AR_KEYTABLE_SIZE;
387f82b4bdeSRajkumar Manoharan 
388f82b4bdeSRajkumar Manoharan 	/*
389f82b4bdeSRajkumar Manoharan 	 * Check whether the separate key cache entries
390f82b4bdeSRajkumar Manoharan 	 * are required to handle both tx+rx MIC keys.
391f82b4bdeSRajkumar Manoharan 	 * With split mic keys the number of stations is limited
392f82b4bdeSRajkumar Manoharan 	 * to 27 otherwise 59.
393f82b4bdeSRajkumar Manoharan 	 */
394f82b4bdeSRajkumar Manoharan 	if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
395f82b4bdeSRajkumar Manoharan 		common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
396f82b4bdeSRajkumar Manoharan 
397f82b4bdeSRajkumar Manoharan 	/*
398f82b4bdeSRajkumar Manoharan 	 * Reset the key cache since some parts do not
399f82b4bdeSRajkumar Manoharan 	 * reset the contents on initial power up.
400f82b4bdeSRajkumar Manoharan 	 */
401f82b4bdeSRajkumar Manoharan 	for (i = 0; i < common->keymax; i++)
402f82b4bdeSRajkumar Manoharan 		ath_hw_keyreset(common, (u16) i);
403f82b4bdeSRajkumar Manoharan }
404f82b4bdeSRajkumar Manoharan EXPORT_SYMBOL(ath9k_cmn_init_crypto);
405f82b4bdeSRajkumar Manoharan 
ath9k_cmn_init(void)406db86f07eSLuis R. Rodriguez static int __init ath9k_cmn_init(void)
407db86f07eSLuis R. Rodriguez {
408db86f07eSLuis R. Rodriguez 	return 0;
409db86f07eSLuis R. Rodriguez }
410db86f07eSLuis R. Rodriguez module_init(ath9k_cmn_init);
411db86f07eSLuis R. Rodriguez 
ath9k_cmn_exit(void)412db86f07eSLuis R. Rodriguez static void __exit ath9k_cmn_exit(void)
413db86f07eSLuis R. Rodriguez {
414db86f07eSLuis R. Rodriguez 	return;
415db86f07eSLuis R. Rodriguez }
416db86f07eSLuis R. Rodriguez module_exit(ath9k_cmn_exit);
417