xref: /linux/drivers/net/wireless/ath/ath9k/common.c (revision 1274603646a82c62776680db85446f767beb9694)
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