blob: 120fd46edf0f989d0675a3ec732c23dcc82558bc [file] [log] [blame]
Luis R. Rodriguezdb86f072009-11-05 08:44:39 -08001/*
Sujith Manoharan5b681382011-05-17 13:36:18 +05302 * Copyright (c) 2009-2011 Atheros Communications Inc.
Luis R. Rodriguezdb86f072009-11-05 08:44:39 -08003 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/*
18 * Module for common driver code between ath9k and ath9k_htc
19 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23
24#include "common.h"
25
26MODULE_AUTHOR("Atheros Communications");
27MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards.");
28MODULE_LICENSE("Dual BSD/GPL");
29
Oleksij Rempel12746032014-02-04 10:27:40 +010030int ath9k_cmn_process_rate(struct ath_common *common,
31 struct ieee80211_hw *hw,
32 struct ath_rx_status *rx_stats,
33 struct ieee80211_rx_status *rxs)
34{
35 struct ieee80211_supported_band *sband;
36 enum ieee80211_band band;
37 unsigned int i = 0;
38 struct ath_hw *ah = common->ah;
39
40 band = ah->curchan->chan->band;
41 sband = hw->wiphy->bands[band];
42
43 if (IS_CHAN_QUARTER_RATE(ah->curchan))
44 rxs->flag |= RX_FLAG_5MHZ;
45 else if (IS_CHAN_HALF_RATE(ah->curchan))
46 rxs->flag |= RX_FLAG_10MHZ;
47
48 if (rx_stats->rs_rate & 0x80) {
49 /* HT rate */
50 rxs->flag |= RX_FLAG_HT;
51 rxs->flag |= rx_stats->flag;
52 rxs->rate_idx = rx_stats->rs_rate & 0x7f;
53 return 0;
54 }
55
56 for (i = 0; i < sband->n_bitrates; i++) {
57 if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
58 rxs->rate_idx = i;
59 return 0;
60 }
61 if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
62 rxs->flag |= RX_FLAG_SHORTPRE;
63 rxs->rate_idx = i;
64 return 0;
65 }
66 }
67
68 return -EINVAL;
69}
70EXPORT_SYMBOL(ath9k_cmn_process_rate);
71
Oleksij Rempel32efb0c2014-02-04 10:27:39 +010072void ath9k_cmn_process_rssi(struct ath_common *common,
73 struct ieee80211_hw *hw,
74 struct ath_rx_status *rx_stats,
75 struct ieee80211_rx_status *rxs)
76{
77 struct ath_hw *ah = common->ah;
78 int last_rssi;
79 int rssi = rx_stats->rs_rssi;
80 int i, j;
81
82 /*
83 * RSSI is not available for subframes in an A-MPDU.
84 */
85 if (rx_stats->rs_moreaggr) {
86 rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
87 return;
88 }
89
90 /*
91 * Check if the RSSI for the last subframe in an A-MPDU
92 * or an unaggregated frame is valid.
93 */
94 if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) {
95 rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
96 return;
97 }
98
99 for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) {
100 s8 rssi;
101
102 if (!(ah->rxchainmask & BIT(i)))
103 continue;
104
105 rssi = rx_stats->rs_rssi_ctl[i];
106 if (rssi != ATH9K_RSSI_BAD) {
107 rxs->chains |= BIT(j);
108 rxs->chain_signal[j] = ah->noise + rssi;
109 }
110 j++;
111 }
112
113 /*
114 * Update Beacon RSSI, this is used by ANI.
115 */
116 if (rx_stats->is_mybeacon &&
117 ((ah->opmode == NL80211_IFTYPE_STATION) ||
118 (ah->opmode == NL80211_IFTYPE_ADHOC))) {
119 ATH_RSSI_LPF(common->last_rssi, rx_stats->rs_rssi);
120 last_rssi = common->last_rssi;
121
122 if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
123 rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
124 if (rssi < 0)
125 rssi = 0;
126
127 ah->stats.avgbrssi = rssi;
128 }
129
130 rxs->signal = ah->noise + rx_stats->rs_rssi;
131}
132EXPORT_SYMBOL(ath9k_cmn_process_rssi);
133
Sujithfb9987d2010-03-17 14:25:25 +0530134int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)
135{
136 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
137
138 if (tx_info->control.hw_key) {
Johannes Berg97359d12010-08-10 09:46:38 +0200139 switch (tx_info->control.hw_key->cipher) {
140 case WLAN_CIPHER_SUITE_WEP40:
141 case WLAN_CIPHER_SUITE_WEP104:
Sujithfb9987d2010-03-17 14:25:25 +0530142 return ATH9K_KEY_TYPE_WEP;
Johannes Berg97359d12010-08-10 09:46:38 +0200143 case WLAN_CIPHER_SUITE_TKIP:
Sujithfb9987d2010-03-17 14:25:25 +0530144 return ATH9K_KEY_TYPE_TKIP;
Johannes Berg97359d12010-08-10 09:46:38 +0200145 case WLAN_CIPHER_SUITE_CCMP:
Sujithfb9987d2010-03-17 14:25:25 +0530146 return ATH9K_KEY_TYPE_AES;
Johannes Berg97359d12010-08-10 09:46:38 +0200147 default:
148 break;
149 }
Sujithfb9987d2010-03-17 14:25:25 +0530150 }
151
152 return ATH9K_KEY_TYPE_CLEAR;
153}
154EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype);
155
Sujithfb9987d2010-03-17 14:25:25 +0530156/*
157 * Update internal channel flags.
158 */
Felix Fietkau2297f1c2013-10-11 23:30:57 +0200159static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
160 struct cfg80211_chan_def *chandef)
Sujithfb9987d2010-03-17 14:25:25 +0530161{
Felix Fietkau6b21fd22013-10-11 23:30:56 +0200162 struct ieee80211_channel *chan = chandef->chan;
163 u16 flags = 0;
Sujithfb9987d2010-03-17 14:25:25 +0530164
Felix Fietkau6b21fd22013-10-11 23:30:56 +0200165 ichan->channel = chan->center_freq;
166 ichan->chan = chan;
167
168 if (chan->band == IEEE80211_BAND_5GHZ)
169 flags |= CHANNEL_5GHZ;
Sujithfb9987d2010-03-17 14:25:25 +0530170
Simon Wunderlich06718942013-08-16 10:46:04 +0200171 switch (chandef->width) {
172 case NL80211_CHAN_WIDTH_5:
Felix Fietkau6b21fd22013-10-11 23:30:56 +0200173 flags |= CHANNEL_QUARTER;
Simon Wunderlich06718942013-08-16 10:46:04 +0200174 break;
175 case NL80211_CHAN_WIDTH_10:
Felix Fietkau6b21fd22013-10-11 23:30:56 +0200176 flags |= CHANNEL_HALF;
Simon Wunderlich06718942013-08-16 10:46:04 +0200177 break;
178 case NL80211_CHAN_WIDTH_20_NOHT:
179 break;
180 case NL80211_CHAN_WIDTH_20:
Felix Fietkau6b21fd22013-10-11 23:30:56 +0200181 flags |= CHANNEL_HT;
182 break;
Simon Wunderlich06718942013-08-16 10:46:04 +0200183 case NL80211_CHAN_WIDTH_40:
Felix Fietkau6b21fd22013-10-11 23:30:56 +0200184 if (chandef->center_freq1 > chandef->chan->center_freq)
185 flags |= CHANNEL_HT40PLUS | CHANNEL_HT;
186 else
187 flags |= CHANNEL_HT40MINUS | CHANNEL_HT;
Simon Wunderlich06718942013-08-16 10:46:04 +0200188 break;
189 default:
190 WARN_ON(1);
191 }
Felix Fietkau6b21fd22013-10-11 23:30:56 +0200192
193 ichan->channelFlags = flags;
Sujithfb9987d2010-03-17 14:25:25 +0530194}
Sujithfb9987d2010-03-17 14:25:25 +0530195
196/*
197 * Get the internal channel reference.
198 */
Felix Fietkau2297f1c2013-10-11 23:30:57 +0200199struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw,
200 struct ath_hw *ah,
201 struct cfg80211_chan_def *chandef)
Sujithfb9987d2010-03-17 14:25:25 +0530202{
Felix Fietkau2297f1c2013-10-11 23:30:57 +0200203 struct ieee80211_channel *curchan = chandef->chan;
Sujithfb9987d2010-03-17 14:25:25 +0530204 struct ath9k_channel *channel;
Sujithfb9987d2010-03-17 14:25:25 +0530205
Felix Fietkauf40c4602013-12-14 18:03:35 +0100206 channel = &ah->channels[curchan->hw_value];
Felix Fietkau2297f1c2013-10-11 23:30:57 +0200207 ath9k_cmn_update_ichannel(channel, chandef);
Sujithfb9987d2010-03-17 14:25:25 +0530208
209 return channel;
210}
Felix Fietkau2297f1c2013-10-11 23:30:57 +0200211EXPORT_SYMBOL(ath9k_cmn_get_channel);
Sujithfb9987d2010-03-17 14:25:25 +0530212
Sujith61389f32010-06-02 15:53:37 +0530213int ath9k_cmn_count_streams(unsigned int chainmask, int max)
214{
215 int streams = 0;
216
217 do {
218 if (++streams == max)
219 break;
220 } while ((chainmask = chainmask & (chainmask - 1)));
221
222 return streams;
223}
224EXPORT_SYMBOL(ath9k_cmn_count_streams);
225
Rajkumar Manoharan5048e8c2011-01-31 23:47:44 +0530226void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
227 u16 new_txpow, u16 *txpower)
228{
Felix Fietkauca2c68c2011-10-08 20:06:20 +0200229 struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
230
231 if (reg->power_limit != new_txpow) {
Rajkumar Manoharan5048e8c2011-01-31 23:47:44 +0530232 ath9k_hw_set_txpowerlimit(ah, new_txpow, false);
233 /* read back in case value is clamped */
Felix Fietkauca2c68c2011-10-08 20:06:20 +0200234 *txpower = reg->max_power_level;
Rajkumar Manoharan5048e8c2011-01-31 23:47:44 +0530235 }
236}
237EXPORT_SYMBOL(ath9k_cmn_update_txpow);
238
Rajkumar Manoharanf82b4bd2011-08-13 10:28:15 +0530239void ath9k_cmn_init_crypto(struct ath_hw *ah)
240{
241 struct ath_common *common = ath9k_hw_common(ah);
242 int i = 0;
243
244 /* Get the hardware key cache size. */
245 common->keymax = AR_KEYTABLE_SIZE;
246
247 /*
248 * Check whether the separate key cache entries
249 * are required to handle both tx+rx MIC keys.
250 * With split mic keys the number of stations is limited
251 * to 27 otherwise 59.
252 */
253 if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
254 common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
255
256 /*
257 * Reset the key cache since some parts do not
258 * reset the contents on initial power up.
259 */
260 for (i = 0; i < common->keymax; i++)
261 ath_hw_keyreset(common, (u16) i);
262}
263EXPORT_SYMBOL(ath9k_cmn_init_crypto);
264
Luis R. Rodriguezdb86f072009-11-05 08:44:39 -0800265static int __init ath9k_cmn_init(void)
266{
267 return 0;
268}
269module_init(ath9k_cmn_init);
270
271static void __exit ath9k_cmn_exit(void)
272{
273 return;
274}
275module_exit(ath9k_cmn_exit);