blob: 9857136627f3d6bd9db63bffa2fc9556941b6946 [file] [log] [blame]
Tomas Winklerdf48c322008-03-06 10:40:19 -08001/******************************************************************************
2 *
Tomas Winklerdf48c322008-03-06 10:40:19 -08003 * GPL LICENSE SUMMARY
4 *
Wey-Yi Guy901069c2011-04-05 09:42:00 -07005 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
Tomas Winklerdf48c322008-03-06 10:40:19 -08006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
19 * USA
20 *
21 * The full GNU General Public License is included in this distribution
22 * in the file called LICENSE.GPL.
23 *
24 * Contact Information:
Winkler, Tomas759ef892008-12-09 11:28:58 -080025 * Intel Linux Wireless <ilw@linux.intel.com>
Tomas Winklerdf48c322008-03-06 10:40:19 -080026 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
27 *****************************************************************************/
28
29#include <linux/kernel.h>
30#include <linux/module.h>
Samuel Ortiz8ccde882009-01-27 14:27:52 -080031#include <linux/etherdevice.h>
Alexey Dobriyand43c36d2009-10-07 17:09:06 +040032#include <linux/sched.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Assaf Krauss1d0a0822008-03-14 10:38:48 -070034#include <net/mac80211.h>
Tomas Winklerdf48c322008-03-06 10:40:19 -080035
Assaf Krauss6bc913b2008-03-11 16:17:18 -070036#include "iwl-eeprom.h"
Tomas Winkler3e0d4cb2008-04-24 11:55:38 -070037#include "iwl-dev.h" /* FIXME: remove */
Winkler, Tomas193357742008-11-07 09:58:36 -080038#include "iwl-debug.h"
Tomas Winklerdf48c322008-03-06 10:40:19 -080039#include "iwl-core.h"
Tomas Winklerb661c812008-04-23 17:14:54 -070040#include "iwl-io.h"
Mohamed Abbas5da4b552008-04-21 15:41:51 -070041#include "iwl-power.h"
Winkler, Tomas83dde8c2008-11-19 15:32:23 -080042#include "iwl-sta.h"
Johannes Bergc6baf7f2011-07-23 10:24:47 -070043#include "iwl-agn.h"
Mohamed Abbasef850d72009-05-22 11:01:50 -070044#include "iwl-helpers.h"
Emmanuel Grumbach48f20d32011-08-25 23:10:36 -070045#include "iwl-shared.h"
Don Fry9d143e92011-04-20 15:23:57 -070046#include "iwl-agn.h"
Emmanuel Grumbachbdfbf092011-07-08 08:46:16 -070047#include "iwl-trans.h"
Tomas Winklerdf48c322008-03-06 10:40:19 -080048
Tomas Winkler57bd1be2008-05-15 13:54:03 +080049const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
Tomas Winkler57bd1be2008-05-15 13:54:03 +080050
Johannes Bergd9fe60d2008-10-09 12:13:49 +020051#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
52#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
Wey-Yi Guyb39488a2011-08-25 23:10:33 -070053static void iwl_init_ht_hw_capab(const struct iwl_priv *priv,
Johannes Bergd9fe60d2008-10-09 12:13:49 +020054 struct ieee80211_sta_ht_cap *ht_info,
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -070055 enum ieee80211_band band)
56{
Ron Rindjunsky39130df2008-05-15 13:53:56 +080057 u16 max_bit_rate = 0;
Emmanuel Grumbachd6189122011-08-25 23:10:39 -070058 u8 rx_chains_num = hw_params(priv).rx_chains_num;
59 u8 tx_chains_num = hw_params(priv).tx_chains_num;
Ron Rindjunsky39130df2008-05-15 13:53:56 +080060
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -070061 ht_info->cap = 0;
Johannes Bergd9fe60d2008-10-09 12:13:49 +020062 memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -070063
Johannes Bergd9fe60d2008-10-09 12:13:49 +020064 ht_info->ht_supported = true;
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -070065
Wey-Yi Guy7cb1b082010-10-06 08:10:00 -070066 if (priv->cfg->ht_params &&
67 priv->cfg->ht_params->ht_greenfield_support)
Daniel C Halperinb2617932009-08-13 13:30:59 -070068 ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
Johannes Bergd9fe60d2008-10-09 12:13:49 +020069 ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
Ron Rindjunsky39130df2008-05-15 13:53:56 +080070 max_bit_rate = MAX_BIT_RATE_20_MHZ;
Emmanuel Grumbachd6189122011-08-25 23:10:39 -070071 if (hw_params(priv).ht40_channel & BIT(band)) {
Johannes Bergd9fe60d2008-10-09 12:13:49 +020072 ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
73 ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
74 ht_info->mcs.rx_mask[4] = 0x01;
Ron Rindjunsky39130df2008-05-15 13:53:56 +080075 max_bit_rate = MAX_BIT_RATE_40_MHZ;
76 }
77
Don Fry9d143e92011-04-20 15:23:57 -070078 if (iwlagn_mod_params.amsdu_size_8K)
Johannes Bergd9fe60d2008-10-09 12:13:49 +020079 ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -070080
81 ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
Wey-Yi Guy7cb1b082010-10-06 08:10:00 -070082 if (priv->cfg->bt_params && priv->cfg->bt_params->ampdu_factor)
83 ht_info->ampdu_factor = priv->cfg->bt_params->ampdu_factor;
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -070084 ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
Wey-Yi Guy7cb1b082010-10-06 08:10:00 -070085 if (priv->cfg->bt_params && priv->cfg->bt_params->ampdu_density)
86 ht_info->ampdu_density = priv->cfg->bt_params->ampdu_density;
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -070087
Johannes Bergd9fe60d2008-10-09 12:13:49 +020088 ht_info->mcs.rx_mask[0] = 0xFF;
Ron Rindjunsky39130df2008-05-15 13:53:56 +080089 if (rx_chains_num >= 2)
Johannes Bergd9fe60d2008-10-09 12:13:49 +020090 ht_info->mcs.rx_mask[1] = 0xFF;
Ron Rindjunsky39130df2008-05-15 13:53:56 +080091 if (rx_chains_num >= 3)
Johannes Bergd9fe60d2008-10-09 12:13:49 +020092 ht_info->mcs.rx_mask[2] = 0xFF;
Ron Rindjunsky39130df2008-05-15 13:53:56 +080093
94 /* Highest supported Rx data rate */
95 max_bit_rate *= rx_chains_num;
Johannes Bergd9fe60d2008-10-09 12:13:49 +020096 WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK);
97 ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate);
Ron Rindjunsky39130df2008-05-15 13:53:56 +080098
99 /* Tx MCS capabilities */
Johannes Bergd9fe60d2008-10-09 12:13:49 +0200100 ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
Ron Rindjunsky39130df2008-05-15 13:53:56 +0800101 if (tx_chains_num != rx_chains_num) {
Johannes Bergd9fe60d2008-10-09 12:13:49 +0200102 ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
103 ht_info->mcs.tx_params |= ((tx_chains_num - 1) <<
104 IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
Ron Rindjunsky39130df2008-05-15 13:53:56 +0800105 }
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700106}
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700107
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700108/**
Wey-Yi Guyb39488a2011-08-25 23:10:33 -0700109 * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700110 */
Wey-Yi Guyb39488a2011-08-25 23:10:33 -0700111int iwl_init_geos(struct iwl_priv *priv)
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700112{
113 struct iwl_channel_info *ch;
114 struct ieee80211_supported_band *sband;
115 struct ieee80211_channel *channels;
116 struct ieee80211_channel *geo_ch;
117 struct ieee80211_rate *rates;
118 int i = 0;
Stanislaw Gruszka75d80ca2011-04-28 11:12:10 +0200119 s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN;
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700120
121 if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
122 priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
Tomas Winklere1623442009-01-27 14:27:56 -0800123 IWL_DEBUG_INFO(priv, "Geography modes already initialized.\n");
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -0700124 set_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status);
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700125 return 0;
126 }
127
128 channels = kzalloc(sizeof(struct ieee80211_channel) *
129 priv->channel_count, GFP_KERNEL);
130 if (!channels)
131 return -ENOMEM;
132
Daniel C Halperin50273092009-08-28 09:44:45 -0700133 rates = kzalloc((sizeof(struct ieee80211_rate) * IWL_RATE_COUNT_LEGACY),
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700134 GFP_KERNEL);
135 if (!rates) {
136 kfree(channels);
137 return -ENOMEM;
138 }
139
140 /* 5.2GHz channels start after the 2.4GHz channels */
141 sband = &priv->bands[IEEE80211_BAND_5GHZ];
142 sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
143 /* just OFDM */
144 sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
Daniel C Halperin50273092009-08-28 09:44:45 -0700145 sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700146
Wey-Yi Guy88950752011-06-06 12:05:46 -0700147 if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
Wey-Yi Guyb39488a2011-08-25 23:10:33 -0700148 iwl_init_ht_hw_capab(priv, &sband->ht_cap,
Ron Rindjunsky49779292008-06-30 17:23:21 +0800149 IEEE80211_BAND_5GHZ);
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700150
151 sband = &priv->bands[IEEE80211_BAND_2GHZ];
152 sband->channels = channels;
153 /* OFDM & CCK */
154 sband->bitrates = rates;
Daniel C Halperin50273092009-08-28 09:44:45 -0700155 sband->n_bitrates = IWL_RATE_COUNT_LEGACY;
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700156
Wey-Yi Guy88950752011-06-06 12:05:46 -0700157 if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
Wey-Yi Guyb39488a2011-08-25 23:10:33 -0700158 iwl_init_ht_hw_capab(priv, &sband->ht_cap,
Ron Rindjunsky49779292008-06-30 17:23:21 +0800159 IEEE80211_BAND_2GHZ);
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700160
161 priv->ieee_channels = channels;
162 priv->ieee_rates = rates;
163
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700164 for (i = 0; i < priv->channel_count; i++) {
165 ch = &priv->channel_info[i];
166
167 /* FIXME: might be removed if scan is OK */
168 if (!is_channel_valid(ch))
169 continue;
170
Stanislaw Gruszka5a3a0352011-01-31 13:01:35 +0100171 sband = &priv->bands[ch->band];
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700172
173 geo_ch = &sband->channels[sband->n_channels++];
174
175 geo_ch->center_freq =
Stanislaw Gruszka5a3a0352011-01-31 13:01:35 +0100176 ieee80211_channel_to_frequency(ch->channel, ch->band);
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700177 geo_ch->max_power = ch->max_power_avg;
178 geo_ch->max_antenna_gain = 0xff;
179 geo_ch->hw_value = ch->channel;
180
181 if (is_channel_valid(ch)) {
182 if (!(ch->flags & EEPROM_CHANNEL_IBSS))
183 geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
184
185 if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
186 geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
187
188 if (ch->flags & EEPROM_CHANNEL_RADAR)
189 geo_ch->flags |= IEEE80211_CHAN_RADAR;
190
Wey-Yi Guy7aafef12009-08-07 15:41:38 -0700191 geo_ch->flags |= ch->ht40_extension_channel;
Emmanuel Grumbach4d38c2e2008-05-29 16:35:24 +0800192
Stanislaw Gruszka75d80ca2011-04-28 11:12:10 +0200193 if (ch->max_power_avg > max_tx_power)
194 max_tx_power = ch->max_power_avg;
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700195 } else {
196 geo_ch->flags |= IEEE80211_CHAN_DISABLED;
197 }
198
Tomas Winklere1623442009-01-27 14:27:56 -0800199 IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n",
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700200 ch->channel, geo_ch->center_freq,
201 is_channel_a_band(ch) ? "5.2" : "2.4",
202 geo_ch->flags & IEEE80211_CHAN_DISABLED ?
203 "restricted" : "valid",
204 geo_ch->flags);
205 }
206
Stanislaw Gruszka75d80ca2011-04-28 11:12:10 +0200207 priv->tx_power_device_lmt = max_tx_power;
208 priv->tx_power_user_lmt = max_tx_power;
209 priv->tx_power_next = max_tx_power;
210
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700211 if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
Wey-Yi Guy88950752011-06-06 12:05:46 -0700212 priv->cfg->sku & EEPROM_SKU_CAP_BAND_52GHZ) {
Emmanuel Grumbach19707ba2011-06-10 11:28:56 -0700213 char buf[32];
Emmanuel Grumbachd5934112011-07-11 10:48:51 +0300214 bus_get_hw_id(priv->bus, buf, sizeof(buf));
Tomas Winkler978785a2008-12-19 10:37:31 +0800215 IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
Emmanuel Grumbach19707ba2011-06-10 11:28:56 -0700216 "Please send your %s to maintainer.\n", buf);
Wey-Yi Guy88950752011-06-06 12:05:46 -0700217 priv->cfg->sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700218 }
219
Tomas Winkler978785a2008-12-19 10:37:31 +0800220 IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n",
Samuel Ortiza3139c52008-12-19 10:37:09 +0800221 priv->bands[IEEE80211_BAND_2GHZ].n_channels,
222 priv->bands[IEEE80211_BAND_5GHZ].n_channels);
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700223
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -0700224 set_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status);
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700225
226 return 0;
227}
228
229/*
Wey-Yi Guyb39488a2011-08-25 23:10:33 -0700230 * iwl_free_geos - undo allocations in iwl_init_geos
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700231 */
Wey-Yi Guyb39488a2011-08-25 23:10:33 -0700232void iwl_free_geos(struct iwl_priv *priv)
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700233{
234 kfree(priv->ieee_channels);
235 kfree(priv->ieee_rates);
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -0700236 clear_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status);
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700237}
Ron Rindjunskyc7de35c2008-04-23 17:15:05 -0700238
Johannes Berg7e6a5882010-08-23 10:46:46 +0200239static bool iwl_is_channel_extension(struct iwl_priv *priv,
240 enum ieee80211_band band,
241 u16 channel, u8 extension_chan_offset)
Tomas Winkler47c51962008-05-05 10:22:41 +0800242{
243 const struct iwl_channel_info *ch_info;
244
245 ch_info = iwl_get_channel_info(priv, band, channel);
246 if (!is_channel_valid(ch_info))
Johannes Berg7e6a5882010-08-23 10:46:46 +0200247 return false;
Tomas Winkler47c51962008-05-05 10:22:41 +0800248
Johannes Bergd9fe60d2008-10-09 12:13:49 +0200249 if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
Wey-Yi Guy7aafef12009-08-07 15:41:38 -0700250 return !(ch_info->ht40_extension_channel &
Luis R. Rodriguez689da1b2009-05-02 00:37:18 -0400251 IEEE80211_CHAN_NO_HT40PLUS);
Johannes Bergd9fe60d2008-10-09 12:13:49 +0200252 else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
Wey-Yi Guy7aafef12009-08-07 15:41:38 -0700253 return !(ch_info->ht40_extension_channel &
Luis R. Rodriguez689da1b2009-05-02 00:37:18 -0400254 IEEE80211_CHAN_NO_HT40MINUS);
Tomas Winkler47c51962008-05-05 10:22:41 +0800255
Johannes Berg7e6a5882010-08-23 10:46:46 +0200256 return false;
Tomas Winkler47c51962008-05-05 10:22:41 +0800257}
258
Johannes Berg7e6a5882010-08-23 10:46:46 +0200259bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
260 struct iwl_rxon_context *ctx,
261 struct ieee80211_sta_ht_cap *ht_cap)
Tomas Winkler47c51962008-05-05 10:22:41 +0800262{
Johannes Berg7e6a5882010-08-23 10:46:46 +0200263 if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
264 return false;
Tomas Winkler47c51962008-05-05 10:22:41 +0800265
Johannes Berg7e6a5882010-08-23 10:46:46 +0200266 /*
267 * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
Wey-Yi Guya2b0f022009-05-22 11:01:49 -0700268 * the bit will not set if it is pure 40MHz case
269 */
Johannes Berg7e6a5882010-08-23 10:46:46 +0200270 if (ht_cap && !ht_cap->ht_supported)
271 return false;
272
Johannes Bergd73e4922010-05-06 12:18:41 -0700273#ifdef CONFIG_IWLWIFI_DEBUGFS
Wey-Yi Guy1e4247d2009-07-27 13:50:15 -0700274 if (priv->disable_ht40)
Johannes Berg7e6a5882010-08-23 10:46:46 +0200275 return false;
Wey-Yi Guy1e4247d2009-07-27 13:50:15 -0700276#endif
Johannes Berg7e6a5882010-08-23 10:46:46 +0200277
Wey-Yi Guy611d3eb2009-06-12 13:22:51 -0700278 return iwl_is_channel_extension(priv, priv->band,
Johannes Berg246ed352010-08-23 10:46:32 +0200279 le16_to_cpu(ctx->staging.channel),
Johannes Berg7e6a5882010-08-23 10:46:46 +0200280 ctx->ht.extension_chan_offset);
Tomas Winkler47c51962008-05-05 10:22:41 +0800281}
Tomas Winkler47c51962008-05-05 10:22:41 +0800282
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700283static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
284{
Johannes Bergea196fd2010-09-03 06:30:55 -0700285 u16 new_val;
286 u16 beacon_factor;
287
288 /*
289 * If mac80211 hasn't given us a beacon interval, program
290 * the default into the device (not checking this here
291 * would cause the adjustment below to return the maximum
292 * value, which may break PAN.)
293 */
294 if (!beacon_val)
295 return DEFAULT_BEACON_INTERVAL;
296
297 /*
298 * If the beacon interval we obtained from the peer
299 * is too large, we'll have to wake up more often
300 * (and in IBSS case, we'll beacon too much)
301 *
302 * For example, if max_beacon_val is 4096, and the
303 * requested beacon interval is 7000, we'll have to
304 * use 3500 to be able to wake up on the beacons.
305 *
306 * This could badly influence beacon detection stats.
307 */
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700308
309 beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
310 new_val = beacon_val / beacon_factor;
311
312 if (!new_val)
313 new_val = max_beacon_val;
314
315 return new_val;
316}
317
Johannes Berg47313e32010-08-23 10:46:55 +0200318int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700319{
320 u64 tsf;
321 s32 interval_tm, rem;
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700322 struct ieee80211_conf *conf = NULL;
323 u16 beacon_int;
Johannes Berg47313e32010-08-23 10:46:55 +0200324 struct ieee80211_vif *vif = ctx->vif;
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700325
326 conf = ieee80211_get_hw_conf(priv->hw);
327
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -0700328 lockdep_assert_held(&priv->shrd->mutex);
Johannes Berg948f5a22010-07-29 07:07:51 -0700329
Johannes Berg246ed352010-08-23 10:46:32 +0200330 memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));
Johannes Berg948f5a22010-07-29 07:07:51 -0700331
Johannes Berg246ed352010-08-23 10:46:32 +0200332 ctx->timing.timestamp = cpu_to_le64(priv->timestamp);
333 ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval);
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700334
Johannes Berg47313e32010-08-23 10:46:55 +0200335 beacon_int = vif ? vif->bss_conf.beacon_int : 0;
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700336
Johannes Berg47313e32010-08-23 10:46:55 +0200337 /*
338 * TODO: For IBSS we need to get atim_window from mac80211,
339 * for now just always use 0
340 */
341 ctx->timing.atim_window = 0;
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700342
Johannes Bergbde45302010-08-23 10:46:57 +0200343 if (ctx->ctxid == IWL_RXON_CTX_PAN &&
Johannes Bergf1f270b2010-09-03 06:31:26 -0700344 (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) &&
345 iwl_is_associated(priv, IWL_RXON_CTX_BSS) &&
346 priv->contexts[IWL_RXON_CTX_BSS].vif &&
347 priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) {
Johannes Bergbde45302010-08-23 10:46:57 +0200348 ctx->timing.beacon_interval =
349 priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval;
350 beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
Johannes Bergf1f270b2010-09-03 06:31:26 -0700351 } else if (ctx->ctxid == IWL_RXON_CTX_BSS &&
352 iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
353 priv->contexts[IWL_RXON_CTX_PAN].vif &&
354 priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int &&
355 (!iwl_is_associated_ctx(ctx) || !ctx->vif ||
356 !ctx->vif->bss_conf.beacon_int)) {
357 ctx->timing.beacon_interval =
358 priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval;
359 beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
Johannes Bergbde45302010-08-23 10:46:57 +0200360 } else {
361 beacon_int = iwl_adjust_beacon_interval(beacon_int,
Emmanuel Grumbachd6189122011-08-25 23:10:39 -0700362 hw_params(priv).max_beacon_itrvl * TIME_UNIT);
Johannes Bergbde45302010-08-23 10:46:57 +0200363 ctx->timing.beacon_interval = cpu_to_le16(beacon_int);
364 }
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700365
Johannes Bergbbb05cb2011-07-18 01:59:22 -0700366 ctx->beacon_int = beacon_int;
367
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700368 tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
Wey-Yi Guyf8525e52010-05-05 11:31:38 -0700369 interval_tm = beacon_int * TIME_UNIT;
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700370 rem = do_div(tsf, interval_tm);
Johannes Berg246ed352010-08-23 10:46:32 +0200371 ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700372
Johannes Berg47313e32010-08-23 10:46:55 +0200373 ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1;
Johannes Berg2491fa42010-08-23 10:46:52 +0200374
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700375 IWL_DEBUG_ASSOC(priv,
376 "beacon interval %d beacon timer %d beacon tim %d\n",
Johannes Berg246ed352010-08-23 10:46:32 +0200377 le16_to_cpu(ctx->timing.beacon_interval),
378 le32_to_cpu(ctx->timing.beacon_init_val),
379 le16_to_cpu(ctx->timing.atim_window));
Johannes Berg948f5a22010-07-29 07:07:51 -0700380
Emmanuel Grumbach41c50542011-07-11 08:51:04 +0300381 return trans_send_cmd_pdu(&priv->trans, ctx->rxon_timing_cmd,
Emmanuel Grumbache419d622011-07-08 08:46:14 -0700382 CMD_SYNC, sizeof(ctx->timing), &ctx->timing);
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700383}
Tomas Winkler2c2f3b32009-06-19 13:52:45 -0700384
Johannes Berg246ed352010-08-23 10:46:32 +0200385void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
386 int hw_decrypt)
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800387{
Johannes Berg246ed352010-08-23 10:46:32 +0200388 struct iwl_rxon_cmd *rxon = &ctx->staging;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800389
390 if (hw_decrypt)
391 rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
392 else
393 rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
394
395}
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800396
Johannes Bergdacefed2010-10-07 04:02:03 -0700397/* validate RXON structure is valid */
Johannes Berg246ed352010-08-23 10:46:32 +0200398int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800399{
Johannes Berg246ed352010-08-23 10:46:32 +0200400 struct iwl_rxon_cmd *rxon = &ctx->staging;
Johannes Bergc914ac22011-04-21 10:57:23 -0700401 u32 errors = 0;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800402
403 if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
Johannes Bergdacefed2010-10-07 04:02:03 -0700404 if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) {
405 IWL_WARN(priv, "check 2.4G: wrong narrow\n");
Johannes Bergc914ac22011-04-21 10:57:23 -0700406 errors |= BIT(0);
Johannes Bergdacefed2010-10-07 04:02:03 -0700407 }
408 if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) {
409 IWL_WARN(priv, "check 2.4G: wrong radar\n");
Johannes Bergc914ac22011-04-21 10:57:23 -0700410 errors |= BIT(1);
Johannes Bergdacefed2010-10-07 04:02:03 -0700411 }
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800412 } else {
Johannes Bergdacefed2010-10-07 04:02:03 -0700413 if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) {
414 IWL_WARN(priv, "check 5.2G: not short slot!\n");
Johannes Bergc914ac22011-04-21 10:57:23 -0700415 errors |= BIT(2);
Johannes Bergdacefed2010-10-07 04:02:03 -0700416 }
417 if (rxon->flags & RXON_FLG_CCK_MSK) {
418 IWL_WARN(priv, "check 5.2G: CCK!\n");
Johannes Bergc914ac22011-04-21 10:57:23 -0700419 errors |= BIT(3);
Johannes Bergdacefed2010-10-07 04:02:03 -0700420 }
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800421 }
Johannes Bergdacefed2010-10-07 04:02:03 -0700422 if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) {
423 IWL_WARN(priv, "mac/bssid mcast!\n");
Johannes Bergc914ac22011-04-21 10:57:23 -0700424 errors |= BIT(4);
Johannes Bergdacefed2010-10-07 04:02:03 -0700425 }
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800426
427 /* make sure basic rates 6Mbps and 1Mbps are supported */
Johannes Bergdacefed2010-10-07 04:02:03 -0700428 if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 &&
429 (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) {
430 IWL_WARN(priv, "neither 1 nor 6 are basic\n");
Johannes Bergc914ac22011-04-21 10:57:23 -0700431 errors |= BIT(5);
Johannes Bergdacefed2010-10-07 04:02:03 -0700432 }
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800433
Johannes Bergdacefed2010-10-07 04:02:03 -0700434 if (le16_to_cpu(rxon->assoc_id) > 2007) {
435 IWL_WARN(priv, "aid > 2007\n");
Johannes Bergc914ac22011-04-21 10:57:23 -0700436 errors |= BIT(6);
Johannes Bergdacefed2010-10-07 04:02:03 -0700437 }
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800438
Johannes Bergdacefed2010-10-07 04:02:03 -0700439 if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
440 == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) {
441 IWL_WARN(priv, "CCK and short slot\n");
Johannes Bergc914ac22011-04-21 10:57:23 -0700442 errors |= BIT(7);
Johannes Bergdacefed2010-10-07 04:02:03 -0700443 }
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800444
Johannes Bergdacefed2010-10-07 04:02:03 -0700445 if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
446 == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) {
447 IWL_WARN(priv, "CCK and auto detect");
Johannes Bergc914ac22011-04-21 10:57:23 -0700448 errors |= BIT(8);
Johannes Bergdacefed2010-10-07 04:02:03 -0700449 }
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800450
Johannes Bergdacefed2010-10-07 04:02:03 -0700451 if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
452 RXON_FLG_TGG_PROTECT_MSK)) ==
453 RXON_FLG_TGG_PROTECT_MSK) {
454 IWL_WARN(priv, "TGg but no auto-detect\n");
Johannes Bergc914ac22011-04-21 10:57:23 -0700455 errors |= BIT(9);
Johannes Bergdacefed2010-10-07 04:02:03 -0700456 }
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800457
Johannes Bergc914ac22011-04-21 10:57:23 -0700458 if (rxon->channel == 0) {
459 IWL_WARN(priv, "zero channel is invalid\n");
460 errors |= BIT(10);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800461 }
Johannes Bergc914ac22011-04-21 10:57:23 -0700462
463 WARN(errors, "Invalid RXON (%#x), channel %d",
464 errors, le16_to_cpu(rxon->channel));
465
466 return errors ? -EINVAL : 0;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800467}
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800468
469/**
470 * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
471 * @priv: staging_rxon is compared to active_rxon
472 *
473 * If the RXON structure is changing enough to require a new tune,
474 * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
475 * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
476 */
Johannes Berg246ed352010-08-23 10:46:32 +0200477int iwl_full_rxon_required(struct iwl_priv *priv,
478 struct iwl_rxon_context *ctx)
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800479{
Johannes Berg246ed352010-08-23 10:46:32 +0200480 const struct iwl_rxon_cmd *staging = &ctx->staging;
481 const struct iwl_rxon_cmd *active = &ctx->active;
482
483#define CHK(cond) \
484 if ((cond)) { \
485 IWL_DEBUG_INFO(priv, "need full RXON - " #cond "\n"); \
486 return 1; \
487 }
488
489#define CHK_NEQ(c1, c2) \
490 if ((c1) != (c2)) { \
491 IWL_DEBUG_INFO(priv, "need full RXON - " \
492 #c1 " != " #c2 " - %d != %d\n", \
493 (c1), (c2)); \
494 return 1; \
495 }
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800496
497 /* These items are only settable from the full RXON command */
Johannes Berg246ed352010-08-23 10:46:32 +0200498 CHK(!iwl_is_associated_ctx(ctx));
499 CHK(compare_ether_addr(staging->bssid_addr, active->bssid_addr));
500 CHK(compare_ether_addr(staging->node_addr, active->node_addr));
501 CHK(compare_ether_addr(staging->wlap_bssid_addr,
502 active->wlap_bssid_addr));
503 CHK_NEQ(staging->dev_type, active->dev_type);
504 CHK_NEQ(staging->channel, active->channel);
505 CHK_NEQ(staging->air_propagation, active->air_propagation);
506 CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates,
507 active->ofdm_ht_single_stream_basic_rates);
508 CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates,
509 active->ofdm_ht_dual_stream_basic_rates);
510 CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates,
511 active->ofdm_ht_triple_stream_basic_rates);
512 CHK_NEQ(staging->assoc_id, active->assoc_id);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800513
514 /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
515 * be updated with the RXON_ASSOC command -- however only some
516 * flag transitions are allowed using RXON_ASSOC */
517
518 /* Check if we are not switching bands */
Johannes Berg246ed352010-08-23 10:46:32 +0200519 CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK,
520 active->flags & RXON_FLG_BAND_24G_MSK);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800521
522 /* Check if we are switching association toggle */
Johannes Berg246ed352010-08-23 10:46:32 +0200523 CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK,
524 active->filter_flags & RXON_FILTER_ASSOC_MSK);
525
526#undef CHK
527#undef CHK_NEQ
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800528
529 return 0;
530}
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800531
Johannes Berg246ed352010-08-23 10:46:32 +0200532static void _iwl_set_rxon_ht(struct iwl_priv *priv,
533 struct iwl_ht_config *ht_conf,
534 struct iwl_rxon_context *ctx)
Tomas Winkler47c51962008-05-05 10:22:41 +0800535{
Johannes Berg246ed352010-08-23 10:46:32 +0200536 struct iwl_rxon_cmd *rxon = &ctx->staging;
Tomas Winkler47c51962008-05-05 10:22:41 +0800537
Johannes Berg7e6a5882010-08-23 10:46:46 +0200538 if (!ctx->ht.enabled) {
Wey-Yi Guya2b0f022009-05-22 11:01:49 -0700539 rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
Emmanuel Grumbach42eb7c62008-09-17 10:10:05 +0800540 RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
Wey-Yi Guy7aafef12009-08-07 15:41:38 -0700541 RXON_FLG_HT40_PROT_MSK |
Emmanuel Grumbach42eb7c62008-09-17 10:10:05 +0800542 RXON_FLG_HT_PROT_MSK);
Tomas Winkler47c51962008-05-05 10:22:41 +0800543 return;
Emmanuel Grumbach42eb7c62008-09-17 10:10:05 +0800544 }
Tomas Winkler47c51962008-05-05 10:22:41 +0800545
Johannes Berg7e6a5882010-08-23 10:46:46 +0200546 /* FIXME: if the definition of ht.protection changed, the "translation"
Wey-Yi Guya2b0f022009-05-22 11:01:49 -0700547 * will be needed for rxon->flags
548 */
Johannes Berg7e6a5882010-08-23 10:46:46 +0200549 rxon->flags |= cpu_to_le32(ctx->ht.protection << RXON_FLG_HT_OPERATING_MODE_POS);
Tomas Winkler47c51962008-05-05 10:22:41 +0800550
Wey-Yi Guya2b0f022009-05-22 11:01:49 -0700551 /* Set up channel bandwidth:
Wey-Yi Guy7aafef12009-08-07 15:41:38 -0700552 * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
Wey-Yi Guya2b0f022009-05-22 11:01:49 -0700553 /* clear the HT channel mode before set the mode */
554 rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
555 RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
Johannes Berg7e6a5882010-08-23 10:46:46 +0200556 if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) {
Wey-Yi Guy7aafef12009-08-07 15:41:38 -0700557 /* pure ht40 */
Johannes Berg7e6a5882010-08-23 10:46:46 +0200558 if (ctx->ht.protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
Wey-Yi Guya2b0f022009-05-22 11:01:49 -0700559 rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
Wey-Yi Guy508b08e2009-06-12 13:22:50 -0700560 /* Note: control channel is opposite of extension channel */
Johannes Berg7e6a5882010-08-23 10:46:46 +0200561 switch (ctx->ht.extension_chan_offset) {
Wey-Yi Guy508b08e2009-06-12 13:22:50 -0700562 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
563 rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
564 break;
565 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
566 rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
567 break;
568 }
569 } else {
Wey-Yi Guya2b0f022009-05-22 11:01:49 -0700570 /* Note: control channel is opposite of extension channel */
Johannes Berg7e6a5882010-08-23 10:46:46 +0200571 switch (ctx->ht.extension_chan_offset) {
Wey-Yi Guya2b0f022009-05-22 11:01:49 -0700572 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
573 rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
574 rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
575 break;
576 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
577 rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
578 rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
579 break;
580 case IEEE80211_HT_PARAM_CHA_SEC_NONE:
581 default:
582 /* channel location only valid if in Mixed mode */
583 IWL_ERR(priv, "invalid extension channel offset\n");
584 break;
585 }
586 }
587 } else {
588 rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
Tomas Winkler47c51962008-05-05 10:22:41 +0800589 }
590
Wey-Yi Guye3f10ce2011-07-01 07:59:26 -0700591 iwlagn_set_rxon_chain(priv, ctx);
Tomas Winkler47c51962008-05-05 10:22:41 +0800592
Johannes Berg02bb1be2009-09-11 10:38:17 -0700593 IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
Johannes Bergae5eb022008-10-14 16:58:37 +0200594 "extension channel offset 0x%x\n",
Johannes Berg7e6a5882010-08-23 10:46:46 +0200595 le32_to_cpu(rxon->flags), ctx->ht.protection,
596 ctx->ht.extension_chan_offset);
Tomas Winkler47c51962008-05-05 10:22:41 +0800597}
Johannes Berg246ed352010-08-23 10:46:32 +0200598
599void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
600{
601 struct iwl_rxon_context *ctx;
602
603 for_each_context(priv, ctx)
604 _iwl_set_rxon_ht(priv, ht_conf, ctx);
605}
Tomas Winkler47c51962008-05-05 10:22:41 +0800606
Johannes Berg246ed352010-08-23 10:46:32 +0200607/* Return valid, unused, channel for a passive scan to reset the RF */
Abhijeet Kolekar14023642010-06-02 21:15:10 -0700608u8 iwl_get_single_channel_number(struct iwl_priv *priv,
Johannes Berg246ed352010-08-23 10:46:32 +0200609 enum ieee80211_band band)
Abhijeet Kolekar14023642010-06-02 21:15:10 -0700610{
611 const struct iwl_channel_info *ch_info;
612 int i;
613 u8 channel = 0;
Johannes Berg246ed352010-08-23 10:46:32 +0200614 u8 min, max;
615 struct iwl_rxon_context *ctx;
Abhijeet Kolekar14023642010-06-02 21:15:10 -0700616
Abhijeet Kolekar14023642010-06-02 21:15:10 -0700617 if (band == IEEE80211_BAND_5GHZ) {
Johannes Berg246ed352010-08-23 10:46:32 +0200618 min = 14;
619 max = priv->channel_count;
Abhijeet Kolekar14023642010-06-02 21:15:10 -0700620 } else {
Johannes Berg246ed352010-08-23 10:46:32 +0200621 min = 0;
622 max = 14;
623 }
624
625 for (i = min; i < max; i++) {
626 bool busy = false;
627
628 for_each_context(priv, ctx) {
629 busy = priv->channel_info[i].channel ==
630 le16_to_cpu(ctx->staging.channel);
631 if (busy)
632 break;
Abhijeet Kolekar14023642010-06-02 21:15:10 -0700633 }
Johannes Berg246ed352010-08-23 10:46:32 +0200634
635 if (busy)
636 continue;
637
638 channel = priv->channel_info[i].channel;
639 ch_info = iwl_get_channel_info(priv, band, channel);
640 if (is_channel_valid(ch_info))
641 break;
Abhijeet Kolekar14023642010-06-02 21:15:10 -0700642 }
643
644 return channel;
645}
Abhijeet Kolekar14023642010-06-02 21:15:10 -0700646
Assaf Kraussbf85ea42008-03-14 10:38:49 -0700647/**
Shanyu Zhao3edb5fd2010-07-27 20:45:15 -0700648 * iwl_set_rxon_channel - Set the band and channel values in staging RXON
649 * @ch: requested channel as a pointer to struct ieee80211_channel
Assaf Kraussbf85ea42008-03-14 10:38:49 -0700650
Assaf Kraussbf85ea42008-03-14 10:38:49 -0700651 * NOTE: Does not commit to the hardware; it sets appropriate bit fields
Shanyu Zhao3edb5fd2010-07-27 20:45:15 -0700652 * in the staging RXON flag structure based on the ch->band
Assaf Kraussbf85ea42008-03-14 10:38:49 -0700653 */
Johannes Berg246ed352010-08-23 10:46:32 +0200654int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
655 struct iwl_rxon_context *ctx)
Assaf Kraussbf85ea42008-03-14 10:38:49 -0700656{
Tomas Winkler17e72782008-09-03 11:26:26 +0800657 enum ieee80211_band band = ch->band;
Shanyu Zhao81e95432010-07-28 13:40:27 -0700658 u16 channel = ch->hw_value;
Tomas Winkler17e72782008-09-03 11:26:26 +0800659
Johannes Berg246ed352010-08-23 10:46:32 +0200660 if ((le16_to_cpu(ctx->staging.channel) == channel) &&
Assaf Kraussbf85ea42008-03-14 10:38:49 -0700661 (priv->band == band))
662 return 0;
663
Johannes Berg246ed352010-08-23 10:46:32 +0200664 ctx->staging.channel = cpu_to_le16(channel);
Assaf Kraussbf85ea42008-03-14 10:38:49 -0700665 if (band == IEEE80211_BAND_5GHZ)
Johannes Berg246ed352010-08-23 10:46:32 +0200666 ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK;
Assaf Kraussbf85ea42008-03-14 10:38:49 -0700667 else
Johannes Berg246ed352010-08-23 10:46:32 +0200668 ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
Assaf Kraussbf85ea42008-03-14 10:38:49 -0700669
670 priv->band = band;
671
Tomas Winklere1623442009-01-27 14:27:56 -0800672 IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band);
Assaf Kraussbf85ea42008-03-14 10:38:49 -0700673
674 return 0;
675}
Assaf Kraussbf85ea42008-03-14 10:38:49 -0700676
Wey-Yi Guy79d07322010-05-06 08:54:11 -0700677void iwl_set_flags_for_band(struct iwl_priv *priv,
Johannes Berg246ed352010-08-23 10:46:32 +0200678 struct iwl_rxon_context *ctx,
Wey-Yi Guy79d07322010-05-06 08:54:11 -0700679 enum ieee80211_band band,
680 struct ieee80211_vif *vif)
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800681{
682 if (band == IEEE80211_BAND_5GHZ) {
Johannes Berg246ed352010-08-23 10:46:32 +0200683 ctx->staging.flags &=
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800684 ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
685 | RXON_FLG_CCK_MSK);
Johannes Berg246ed352010-08-23 10:46:32 +0200686 ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800687 } else {
688 /* Copied from iwl_post_associate() */
Johannes Bergc213d742010-05-06 12:21:40 -0700689 if (vif && vif->bss_conf.use_short_slot)
Johannes Berg246ed352010-08-23 10:46:32 +0200690 ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800691 else
Johannes Berg246ed352010-08-23 10:46:32 +0200692 ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800693
Johannes Berg246ed352010-08-23 10:46:32 +0200694 ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
695 ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK;
696 ctx->staging.flags &= ~RXON_FLG_CCK_MSK;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800697 }
698}
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800699
700/*
701 * initialize rxon structure with default values from eeprom
702 */
Johannes Berg1dda6d22010-04-29 04:43:06 -0700703void iwl_connection_init_rx_config(struct iwl_priv *priv,
Johannes Bergd0fe4782010-08-23 10:46:58 +0200704 struct iwl_rxon_context *ctx)
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800705{
706 const struct iwl_channel_info *ch_info;
707
Johannes Berg246ed352010-08-23 10:46:32 +0200708 memset(&ctx->staging, 0, sizeof(ctx->staging));
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800709
Johannes Bergd0fe4782010-08-23 10:46:58 +0200710 if (!ctx->vif) {
711 ctx->staging.dev_type = ctx->unused_devtype;
712 } else switch (ctx->vif->type) {
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800713 case NL80211_IFTYPE_AP:
Johannes Bergd0fe4782010-08-23 10:46:58 +0200714 ctx->staging.dev_type = ctx->ap_devtype;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800715 break;
716
717 case NL80211_IFTYPE_STATION:
Johannes Bergd0fe4782010-08-23 10:46:58 +0200718 ctx->staging.dev_type = ctx->station_devtype;
Johannes Berg246ed352010-08-23 10:46:32 +0200719 ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800720 break;
721
722 case NL80211_IFTYPE_ADHOC:
Johannes Bergd0fe4782010-08-23 10:46:58 +0200723 ctx->staging.dev_type = ctx->ibss_devtype;
Johannes Berg246ed352010-08-23 10:46:32 +0200724 ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
725 ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800726 RXON_FILTER_ACCEPT_GRP_MSK;
727 break;
728
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800729 default:
Johannes Bergd0fe4782010-08-23 10:46:58 +0200730 IWL_ERR(priv, "Unsupported interface type %d\n",
731 ctx->vif->type);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800732 break;
733 }
734
735#if 0
736 /* TODO: Figure out when short_preamble would be set and cache from
737 * that */
738 if (!hw_to_local(priv->hw)->short_preamble)
Johannes Berg246ed352010-08-23 10:46:32 +0200739 ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800740 else
Johannes Berg246ed352010-08-23 10:46:32 +0200741 ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800742#endif
743
744 ch_info = iwl_get_channel_info(priv, priv->band,
Johannes Berg246ed352010-08-23 10:46:32 +0200745 le16_to_cpu(ctx->active.channel));
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800746
747 if (!ch_info)
748 ch_info = &priv->channel_info[0];
749
Johannes Berg246ed352010-08-23 10:46:32 +0200750 ctx->staging.channel = cpu_to_le16(ch_info->channel);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800751 priv->band = ch_info->band;
752
Johannes Bergd0fe4782010-08-23 10:46:58 +0200753 iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800754
Johannes Berg246ed352010-08-23 10:46:32 +0200755 ctx->staging.ofdm_basic_rates =
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800756 (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
Johannes Berg246ed352010-08-23 10:46:32 +0200757 ctx->staging.cck_basic_rates =
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800758 (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
759
Wey-Yi Guya2b0f022009-05-22 11:01:49 -0700760 /* clear both MIX and PURE40 mode flag */
Johannes Berg246ed352010-08-23 10:46:32 +0200761 ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
Wey-Yi Guya2b0f022009-05-22 11:01:49 -0700762 RXON_FLG_CHANNEL_MODE_PURE_40);
Johannes Bergd0fe4782010-08-23 10:46:58 +0200763 if (ctx->vif)
764 memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);
Johannes Berg7684c402010-05-12 03:33:11 -0700765
Johannes Berg246ed352010-08-23 10:46:32 +0200766 ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff;
767 ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff;
768 ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800769}
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800770
Wey-Yi Guy79d07322010-05-06 08:54:11 -0700771void iwl_set_rate(struct iwl_priv *priv)
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800772{
773 const struct ieee80211_supported_band *hw = NULL;
774 struct ieee80211_rate *rate;
Johannes Berg246ed352010-08-23 10:46:32 +0200775 struct iwl_rxon_context *ctx;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800776 int i;
777
778 hw = iwl_get_hw_mode(priv, priv->band);
779 if (!hw) {
780 IWL_ERR(priv, "Failed to set rate: unable to get hw mode\n");
781 return;
782 }
783
784 priv->active_rate = 0;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800785
786 for (i = 0; i < hw->n_bitrates; i++) {
787 rate = &(hw->bitrates[i]);
Daniel C Halperin50273092009-08-28 09:44:45 -0700788 if (rate->hw_value < IWL_RATE_COUNT_LEGACY)
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800789 priv->active_rate |= (1 << rate->hw_value);
790 }
791
Johannes Berg4a028862010-01-21 11:33:19 -0800792 IWL_DEBUG_RATE(priv, "Set active_rate = %0x\n", priv->active_rate);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800793
Johannes Berg246ed352010-08-23 10:46:32 +0200794 for_each_context(priv, ctx) {
795 ctx->staging.cck_basic_rates =
796 (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800797
Johannes Berg246ed352010-08-23 10:46:32 +0200798 ctx->staging.ofdm_basic_rates =
799 (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
800 }
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800801}
Wey-Yi Guy79d07322010-05-06 08:54:11 -0700802
803void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
804{
Johannes Berg8bd413e2010-08-23 10:46:40 +0200805 /*
806 * MULTI-FIXME
807 * See iwl_mac_channel_switch.
808 */
809 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
810
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -0700811 if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
Wey-Yi Guy79d07322010-05-06 08:54:11 -0700812 return;
813
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -0700814 if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING,
815 &priv->shrd->status))
Johannes Berg8bd413e2010-08-23 10:46:40 +0200816 ieee80211_chswitch_done(ctx->vif, is_success);
Wey-Yi Guy79d07322010-05-06 08:54:11 -0700817}
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800818
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800819#ifdef CONFIG_IWLWIFI_DEBUG
Johannes Berg246ed352010-08-23 10:46:32 +0200820void iwl_print_rx_config_cmd(struct iwl_priv *priv,
821 struct iwl_rxon_context *ctx)
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800822{
Johannes Berg246ed352010-08-23 10:46:32 +0200823 struct iwl_rxon_cmd *rxon = &ctx->staging;
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800824
Tomas Winklere1623442009-01-27 14:27:56 -0800825 IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
Reinette Chatre3d816c72009-08-07 15:41:37 -0700826 iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
Tomas Winklere1623442009-01-27 14:27:56 -0800827 IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
828 IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
829 IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800830 le32_to_cpu(rxon->filter_flags));
Tomas Winklere1623442009-01-27 14:27:56 -0800831 IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type);
832 IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n",
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800833 rxon->ofdm_basic_rates);
Tomas Winklere1623442009-01-27 14:27:56 -0800834 IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
835 IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr);
836 IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
837 IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800838}
Reinette Chatre6686d172009-07-24 11:13:13 -0700839#endif
Johannes Berge6494372011-04-05 09:41:58 -0700840
Johannes Berge74fe232011-04-13 03:14:49 -0700841static void iwlagn_abort_notification_waits(struct iwl_priv *priv)
842{
843 unsigned long flags;
844 struct iwl_notification_wait *wait_entry;
845
Wey-Yi Guy898ed672011-07-13 08:38:57 -0700846 spin_lock_irqsave(&priv->notif_wait_lock, flags);
847 list_for_each_entry(wait_entry, &priv->notif_waits, list)
Johannes Berge74fe232011-04-13 03:14:49 -0700848 wait_entry->aborted = true;
Wey-Yi Guy898ed672011-07-13 08:38:57 -0700849 spin_unlock_irqrestore(&priv->notif_wait_lock, flags);
Johannes Berge74fe232011-04-13 03:14:49 -0700850
Wey-Yi Guy898ed672011-07-13 08:38:57 -0700851 wake_up_all(&priv->notif_waitq);
Johannes Berge74fe232011-04-13 03:14:49 -0700852}
853
Johannes Berge6494372011-04-05 09:41:58 -0700854void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800855{
Wey-Yi Guy491bc292011-02-09 09:37:46 -0800856 unsigned int reload_msec;
857 unsigned long reload_jiffies;
858
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800859 /* Set the FW error flag -- cleared on iwl_down */
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -0700860 set_bit(STATUS_FW_ERROR, &priv->shrd->status);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800861
862 /* Cancel currently queued command. */
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -0700863 clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800864
Johannes Berge74fe232011-04-13 03:14:49 -0700865 iwlagn_abort_notification_waits(priv);
866
Johannes Berge6494372011-04-05 09:41:58 -0700867 /* Keep the restart process from trying to send host
868 * commands by clearing the ready bit */
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -0700869 clear_bit(STATUS_READY, &priv->shrd->status);
Johannes Berge6494372011-04-05 09:41:58 -0700870
871 wake_up_interruptible(&priv->wait_command_queue);
872
873 if (!ondemand) {
874 /*
875 * If firmware keep reloading, then it indicate something
876 * serious wrong and firmware having problem to recover
877 * from it. Instead of keep trying which will fill the syslog
878 * and hang the system, let's just stop it
879 */
880 reload_jiffies = jiffies;
881 reload_msec = jiffies_to_msecs((long) reload_jiffies -
882 (long) priv->reload_jiffies);
883 priv->reload_jiffies = reload_jiffies;
884 if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
885 priv->reload_count++;
886 if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
887 IWL_ERR(priv, "BUG_ON, Stop restarting\n");
888 return;
889 }
890 } else
891 priv->reload_count = 0;
892 }
893
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -0700894 if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
Don Fry9d143e92011-04-20 15:23:57 -0700895 if (iwlagn_mod_params.restart_fw) {
Emmanuel Grumbach9ca06f02011-08-25 23:10:46 -0700896 IWL_DEBUG_FW_ERRORS(priv,
Johannes Berge6494372011-04-05 09:41:58 -0700897 "Restarting adapter due to uCode error.\n");
Emmanuel Grumbach74e28e42011-08-25 23:10:41 -0700898 queue_work(priv->shrd->workqueue, &priv->restart);
Johannes Berge6494372011-04-05 09:41:58 -0700899 } else
Emmanuel Grumbach9ca06f02011-08-25 23:10:46 -0700900 IWL_DEBUG_FW_ERRORS(priv,
Johannes Berge6494372011-04-05 09:41:58 -0700901 "Detected FW error, but not restarting\n");
902 }
903}
904
905/**
906 * iwl_irq_handle_error - called for HW or SW error interrupt from card
907 */
908void iwl_irq_handle_error(struct iwl_priv *priv)
909{
Wey-Yi Guy50619ac2010-12-07 08:06:31 -0800910 /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
911 if (priv->cfg->internal_wimax_coex &&
912 (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) &
913 APMS_CLK_VAL_MRB_FUNC_MODE) ||
914 (iwl_read_prph(priv, APMG_PS_CTRL_REG) &
915 APMG_PS_CTRL_VAL_RESET_REQ))) {
Wey-Yi Guy50619ac2010-12-07 08:06:31 -0800916 /*
Johannes Berge6494372011-04-05 09:41:58 -0700917 * Keep the restart process from trying to send host
918 * commands by clearing the ready bit.
Wey-Yi Guy50619ac2010-12-07 08:06:31 -0800919 */
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -0700920 clear_bit(STATUS_READY, &priv->shrd->status);
921 clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status);
Johannes Berge6494372011-04-05 09:41:58 -0700922 wake_up_interruptible(&priv->wait_command_queue);
Wey-Yi Guy50619ac2010-12-07 08:06:31 -0800923 IWL_ERR(priv, "RF is used by WiMAX\n");
924 return;
925 }
926
Shanyu Zhao459bc732010-04-27 22:05:15 -0700927 IWL_ERR(priv, "Loaded firmware version: %s\n",
928 priv->hw->wiphy->fw_version);
929
Wey-Yi Guy3ecccbc2011-03-29 17:53:15 -0700930 iwl_dump_nic_error_log(priv);
931 iwl_dump_csr(priv);
932 iwl_dump_fh(priv, NULL, false);
933 iwl_dump_nic_event_log(priv, false, NULL, false);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800934#ifdef CONFIG_IWLWIFI_DEBUG
Emmanuel Grumbach8f470ce2011-08-25 23:10:38 -0700935 if (iwl_get_debug_level(priv->shrd) & IWL_DL_FW_ERRORS)
Johannes Berg246ed352010-08-23 10:46:32 +0200936 iwl_print_rx_config_cmd(priv,
937 &priv->contexts[IWL_RXON_CTX_BSS]);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800938#endif
939
Johannes Berge6494372011-04-05 09:41:58 -0700940 iwlagn_fw_error(priv, false);
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800941}
Samuel Ortiz8ccde882009-01-27 14:27:52 -0800942
Reinette Chatref8e200d2010-02-19 11:41:32 -0800943static int iwl_apm_stop_master(struct iwl_priv *priv)
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700944{
Ben Cahill5220af02009-10-30 14:36:05 -0700945 int ret = 0;
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700946
Ben Cahill5220af02009-10-30 14:36:05 -0700947 /* stop device's busmaster DMA activity */
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700948 iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
949
Ben Cahill5220af02009-10-30 14:36:05 -0700950 ret = iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED,
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700951 CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
Ben Cahill5220af02009-10-30 14:36:05 -0700952 if (ret)
953 IWL_WARN(priv, "Master Disable Timed Out, 100 usec\n");
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700954
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700955 IWL_DEBUG_INFO(priv, "stop master\n");
956
Ben Cahill5220af02009-10-30 14:36:05 -0700957 return ret;
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700958}
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700959
960void iwl_apm_stop(struct iwl_priv *priv)
961{
Ben Cahillfadb3582009-10-23 13:42:21 -0700962 IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n");
963
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -0700964 clear_bit(STATUS_DEVICE_ENABLED, &priv->shrd->status);
Johannes Berg9d39e5b2011-04-19 07:38:23 -0700965
Ben Cahill5220af02009-10-30 14:36:05 -0700966 /* Stop device's DMA activity */
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700967 iwl_apm_stop_master(priv);
968
Ben Cahill5220af02009-10-30 14:36:05 -0700969 /* Reset the entire device */
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700970 iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
971
972 udelay(10);
Ben Cahill5220af02009-10-30 14:36:05 -0700973
974 /*
975 * Clear "initialization complete" bit to move adapter from
976 * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
977 */
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700978 iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700979}
Abhijeet Kolekard68b6032009-10-02 13:44:04 -0700980
Ben Cahillfadb3582009-10-23 13:42:21 -0700981
982/*
983 * Start up NIC's basic functionality after it has been reset
984 * (e.g. after platform boot, or shutdown via iwl_apm_stop())
985 * NOTE: This does not load uCode nor start the embedded processor
986 */
987int iwl_apm_init(struct iwl_priv *priv)
988{
989 int ret = 0;
Ben Cahillfadb3582009-10-23 13:42:21 -0700990 IWL_DEBUG_INFO(priv, "Init card's basic functions\n");
991
992 /*
993 * Use "set_bit" below rather than "write", to preserve any hardware
994 * bits already set by default after reset.
995 */
996
997 /* Disable L0S exit timer (platform NMI Work/Around) */
998 iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
999 CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
1000
1001 /*
1002 * Disable L0s without affecting L1;
1003 * don't wait for ICH L0s (ICH bug W/A)
1004 */
1005 iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
1006 CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
1007
1008 /* Set FH wait threshold to maximum (HW error during stress W/A) */
1009 iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
1010
1011 /*
1012 * Enable HAP INTA (interrupt from management bus) to
1013 * wake device's PCI Express link L1a -> L0s
Ben Cahillfadb3582009-10-23 13:42:21 -07001014 */
1015 iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
1016 CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
1017
Emmanuel Grumbachd5934112011-07-11 10:48:51 +03001018 bus_apm_config(priv->bus);
Ben Cahillfadb3582009-10-23 13:42:21 -07001019
1020 /* Configure analog phase-lock-loop before activating to D0A */
Wey-Yi Guy7cb1b082010-10-06 08:10:00 -07001021 if (priv->cfg->base_params->pll_cfg_val)
1022 iwl_set_bit(priv, CSR_ANA_PLL_CFG,
1023 priv->cfg->base_params->pll_cfg_val);
Ben Cahillfadb3582009-10-23 13:42:21 -07001024
1025 /*
1026 * Set "initialization complete" bit to move adapter from
1027 * D0U* --> D0A* (powered-up active) state.
1028 */
1029 iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
1030
1031 /*
1032 * Wait for clock stabilization; once stabilized, access to
1033 * device-internal resources is supported, e.g. iwl_write_prph()
1034 * and accesses to uCode SRAM.
1035 */
1036 ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
1037 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
1038 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
1039 if (ret < 0) {
1040 IWL_DEBUG_INFO(priv, "Failed to init the card\n");
1041 goto out;
1042 }
1043
1044 /*
Johannes Berg917b6772011-04-05 09:42:06 -07001045 * Enable DMA clock and wait for it to stabilize.
Ben Cahillfadb3582009-10-23 13:42:21 -07001046 *
1047 * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
1048 * do not disable clocks. This preserves any hardware bits already
1049 * set by default in "CLK_CTRL_REG" after reset.
1050 */
Johannes Berg917b6772011-04-05 09:42:06 -07001051 iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
Ben Cahillfadb3582009-10-23 13:42:21 -07001052 udelay(20);
1053
1054 /* Disable L1-Active */
1055 iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
1056 APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
1057
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -07001058 set_bit(STATUS_DEVICE_ENABLED, &priv->shrd->status);
Johannes Berg9d39e5b2011-04-19 07:38:23 -07001059
Ben Cahillfadb3582009-10-23 13:42:21 -07001060out:
1061 return ret;
1062}
Ben Cahillfadb3582009-10-23 13:42:21 -07001063
1064
Tomas Winkler630fe9b2008-06-12 09:47:08 +08001065int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
1066{
Stanislaw Gruszkaa25a66a2010-10-22 17:04:26 +02001067 int ret;
1068 s8 prev_tx_power;
Stanislaw Gruszkaf844a702011-01-28 16:47:44 +01001069 bool defer;
1070 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
Stanislaw Gruszkaa25a66a2010-10-22 17:04:26 +02001071
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -07001072 lockdep_assert_held(&priv->shrd->mutex);
Stanislaw Gruszkaa25a66a2010-10-22 17:04:26 +02001073
1074 if (priv->tx_power_user_lmt == tx_power && !force)
1075 return 0;
1076
Wey-Yi Guyb744cb72010-03-23 11:37:59 -07001077 if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
1078 IWL_WARN(priv,
1079 "Requested user TXPOWER %d below lower limit %d.\n",
Wu, Fengguangdaf518d2009-02-13 11:51:17 -08001080 tx_power,
Wey-Yi Guyb744cb72010-03-23 11:37:59 -07001081 IWLAGN_TX_POWER_TARGET_POWER_MIN);
Tomas Winkler630fe9b2008-06-12 09:47:08 +08001082 return -EINVAL;
1083 }
1084
Wey-Yi Guydc1b0972009-08-21 13:34:16 -07001085 if (tx_power > priv->tx_power_device_lmt) {
Wey-Yi Guy08f2d582009-08-21 13:34:15 -07001086 IWL_WARN(priv,
1087 "Requested user TXPOWER %d above upper limit %d.\n",
Wey-Yi Guydc1b0972009-08-21 13:34:16 -07001088 tx_power, priv->tx_power_device_lmt);
Tomas Winkler630fe9b2008-06-12 09:47:08 +08001089 return -EINVAL;
1090 }
1091
Stanislaw Gruszkaa25a66a2010-10-22 17:04:26 +02001092 if (!iwl_is_ready_rf(priv))
1093 return -EIO;
Tomas Winkler630fe9b2008-06-12 09:47:08 +08001094
Stanislaw Gruszkaf844a702011-01-28 16:47:44 +01001095 /* scan complete and commit_rxon use tx_power_next value,
1096 * it always need to be updated for newest request */
Stanislaw Gruszkaa25a66a2010-10-22 17:04:26 +02001097 priv->tx_power_next = tx_power;
Stanislaw Gruszkaf844a702011-01-28 16:47:44 +01001098
1099 /* do not set tx power when scanning or channel changing */
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -07001100 defer = test_bit(STATUS_SCANNING, &priv->shrd->status) ||
Stanislaw Gruszkaf844a702011-01-28 16:47:44 +01001101 memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
1102 if (defer && !force) {
1103 IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
Stanislaw Gruszkaa25a66a2010-10-22 17:04:26 +02001104 return 0;
Wey-Yi Guy5eadd942009-08-21 13:34:17 -07001105 }
Mohamed Abbas019fb972009-03-17 21:59:18 -07001106
Stanislaw Gruszkaa25a66a2010-10-22 17:04:26 +02001107 prev_tx_power = priv->tx_power_user_lmt;
1108 priv->tx_power_user_lmt = tx_power;
1109
Wey-Yi Guy5beaaf32011-05-27 08:40:25 -07001110 ret = iwlagn_send_tx_power(priv);
Stanislaw Gruszkaa25a66a2010-10-22 17:04:26 +02001111
1112 /* if fail to set tx_power, restore the orig. tx power */
1113 if (ret) {
1114 priv->tx_power_user_lmt = prev_tx_power;
1115 priv->tx_power_next = prev_tx_power;
1116 }
Tomas Winkler630fe9b2008-06-12 09:47:08 +08001117 return ret;
1118}
Tomas Winkler630fe9b2008-06-12 09:47:08 +08001119
Johannes Berg65b52bd2010-04-13 01:04:31 -07001120void iwl_send_bt_config(struct iwl_priv *priv)
Samuel Ortiz17f841c2009-01-23 13:45:20 -08001121{
1122 struct iwl_bt_cmd bt_cmd = {
Wey-Yi Guy456d0f72009-10-23 13:42:23 -07001123 .lead_time = BT_LEAD_TIME_DEF,
1124 .max_kill = BT_MAX_KILL_DEF,
Samuel Ortiz17f841c2009-01-23 13:45:20 -08001125 .kill_ack_mask = 0,
1126 .kill_cts_mask = 0,
1127 };
1128
Wey-Yi Guyb60eec92011-06-03 13:52:38 -07001129 if (!iwlagn_mod_params.bt_coex_active)
Wey-Yi Guy06702a72010-01-22 14:22:51 -08001130 bt_cmd.flags = BT_COEX_DISABLE;
1131 else
1132 bt_cmd.flags = BT_COEX_ENABLE;
1133
Wey-Yi Guyf21dd002010-12-08 15:34:52 -08001134 priv->bt_enable_flag = bt_cmd.flags;
Wey-Yi Guy06702a72010-01-22 14:22:51 -08001135 IWL_DEBUG_INFO(priv, "BT coex %s\n",
1136 (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
1137
Emmanuel Grumbach41c50542011-07-11 08:51:04 +03001138 if (trans_send_cmd_pdu(&priv->trans, REPLY_BT_CONFIG,
Emmanuel Grumbache419d622011-07-08 08:46:14 -07001139 CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
Johannes Berg65b52bd2010-04-13 01:04:31 -07001140 IWL_ERR(priv, "failed to send BT Coex Config\n");
Samuel Ortiz17f841c2009-01-23 13:45:20 -08001141}
Samuel Ortiz17f841c2009-01-23 13:45:20 -08001142
Wey-Yi Guyef8d5522009-11-13 11:56:28 -08001143int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
Emmanuel Grumbach49ea8592008-04-15 16:01:37 -07001144{
Wey-Yi Guyef8d5522009-11-13 11:56:28 -08001145 struct iwl_statistics_cmd statistics_cmd = {
1146 .configuration_flags =
1147 clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
Emmanuel Grumbach49ea8592008-04-15 16:01:37 -07001148 };
Wey-Yi Guyef8d5522009-11-13 11:56:28 -08001149
1150 if (flags & CMD_ASYNC)
Emmanuel Grumbach41c50542011-07-11 08:51:04 +03001151 return trans_send_cmd_pdu(&priv->trans, REPLY_STATISTICS_CMD,
Emmanuel Grumbache419d622011-07-08 08:46:14 -07001152 CMD_ASYNC,
Wey-Yi Guyef8d5522009-11-13 11:56:28 -08001153 sizeof(struct iwl_statistics_cmd),
Emmanuel Grumbache419d622011-07-08 08:46:14 -07001154 &statistics_cmd);
Wey-Yi Guyef8d5522009-11-13 11:56:28 -08001155 else
Emmanuel Grumbach41c50542011-07-11 08:51:04 +03001156 return trans_send_cmd_pdu(&priv->trans, REPLY_STATISTICS_CMD,
Emmanuel Grumbache419d622011-07-08 08:46:14 -07001157 CMD_SYNC,
Wey-Yi Guyef8d5522009-11-13 11:56:28 -08001158 sizeof(struct iwl_statistics_cmd),
1159 &statistics_cmd);
Emmanuel Grumbach49ea8592008-04-15 16:01:37 -07001160}
Tomas Winkler7e8c5192008-04-15 16:01:43 -07001161
Wey-Yi Guya83b9142009-04-08 11:39:32 -07001162void iwl_clear_isr_stats(struct iwl_priv *priv)
1163{
1164 memset(&priv->isr_stats, 0, sizeof(priv->isr_stats));
1165}
Wey-Yi Guya83b9142009-04-08 11:39:32 -07001166
Abhijeet Kolekar488829f2009-03-26 10:14:10 -07001167int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
1168 const struct ieee80211_tx_queue_params *params)
1169{
1170 struct iwl_priv *priv = hw->priv;
Johannes Berg8dfdb9d2010-08-23 10:46:38 +02001171 struct iwl_rxon_context *ctx;
Abhijeet Kolekar488829f2009-03-26 10:14:10 -07001172 unsigned long flags;
1173 int q;
1174
1175 IWL_DEBUG_MAC80211(priv, "enter\n");
1176
1177 if (!iwl_is_ready_rf(priv)) {
1178 IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
1179 return -EIO;
1180 }
1181
1182 if (queue >= AC_NUM) {
1183 IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
1184 return 0;
1185 }
1186
1187 q = AC_NUM - 1 - queue;
1188
Emmanuel Grumbach10b15e62011-08-25 23:10:43 -07001189 spin_lock_irqsave(&priv->shrd->lock, flags);
Abhijeet Kolekar488829f2009-03-26 10:14:10 -07001190
Johannes Berg8dfdb9d2010-08-23 10:46:38 +02001191 /*
1192 * MULTI-FIXME
1193 * This may need to be done per interface in nl80211/cfg80211/mac80211.
1194 */
1195 for_each_context(priv, ctx) {
1196 ctx->qos_data.def_qos_parm.ac[q].cw_min =
1197 cpu_to_le16(params->cw_min);
1198 ctx->qos_data.def_qos_parm.ac[q].cw_max =
1199 cpu_to_le16(params->cw_max);
1200 ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
1201 ctx->qos_data.def_qos_parm.ac[q].edca_txop =
1202 cpu_to_le16((params->txop * 32));
Abhijeet Kolekar488829f2009-03-26 10:14:10 -07001203
Johannes Berg8dfdb9d2010-08-23 10:46:38 +02001204 ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
1205 }
Abhijeet Kolekar488829f2009-03-26 10:14:10 -07001206
Emmanuel Grumbach10b15e62011-08-25 23:10:43 -07001207 spin_unlock_irqrestore(&priv->shrd->lock, flags);
Abhijeet Kolekar488829f2009-03-26 10:14:10 -07001208
1209 IWL_DEBUG_MAC80211(priv, "leave\n");
1210 return 0;
1211}
Abhijeet Kolekar5bbe2332009-04-08 11:26:35 -07001212
Johannes Berga85d7cc2010-07-31 08:34:10 -07001213int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw)
1214{
1215 struct iwl_priv *priv = hw->priv;
1216
1217 return priv->ibss_manager == IWL_IBSS_MANAGER;
1218}
Johannes Berga85d7cc2010-07-31 08:34:10 -07001219
Johannes Bergd4daaea2010-10-23 09:15:43 -07001220static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
Abhijeet Kolekar727882d2009-04-08 11:26:45 -07001221{
Johannes Bergd0fe4782010-08-23 10:46:58 +02001222 iwl_connection_init_rx_config(priv, ctx);
Abhijeet Kolekar727882d2009-04-08 11:26:45 -07001223
Wey-Yi Guye3f10ce2011-07-01 07:59:26 -07001224 iwlagn_set_rxon_chain(priv, ctx);
Abhijeet Kolekar727882d2009-04-08 11:26:45 -07001225
Wey-Yi Guy805a3b82011-06-03 07:54:16 -07001226 return iwlagn_commit_rxon(priv, ctx);
Abhijeet Kolekar727882d2009-04-08 11:26:45 -07001227}
Abhijeet Kolekar727882d2009-04-08 11:26:45 -07001228
Johannes Bergd4daaea2010-10-23 09:15:43 -07001229static int iwl_setup_interface(struct iwl_priv *priv,
1230 struct iwl_rxon_context *ctx)
1231{
1232 struct ieee80211_vif *vif = ctx->vif;
1233 int err;
1234
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -07001235 lockdep_assert_held(&priv->shrd->mutex);
Johannes Bergd4daaea2010-10-23 09:15:43 -07001236
1237 /*
1238 * This variable will be correct only when there's just
1239 * a single context, but all code using it is for hardware
1240 * that supports only one context.
1241 */
1242 priv->iw_mode = vif->type;
1243
1244 ctx->is_active = true;
1245
1246 err = iwl_set_mode(priv, ctx);
1247 if (err) {
1248 if (!ctx->always_active)
1249 ctx->is_active = false;
1250 return err;
1251 }
1252
1253 if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
1254 vif->type == NL80211_IFTYPE_ADHOC) {
1255 /*
1256 * pretend to have high BT traffic as long as we
1257 * are operating in IBSS mode, as this will cause
1258 * the rate scaling etc. to behave as intended.
1259 */
1260 priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
1261 }
1262
1263 return 0;
1264}
1265
Johannes Bergb55e75e2010-02-17 04:54:08 -08001266int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
Abhijeet Kolekarcbb6ab92009-04-08 11:26:46 -07001267{
1268 struct iwl_priv *priv = hw->priv;
Johannes Berg246ed352010-08-23 10:46:32 +02001269 struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
Johannes Bergd0fe4782010-08-23 10:46:58 +02001270 struct iwl_rxon_context *tmp, *ctx = NULL;
Johannes Bergd4daaea2010-10-23 09:15:43 -07001271 int err;
Wey-Yi Guyf35c0c52011-01-13 17:09:29 -08001272 enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
Abhijeet Kolekarcbb6ab92009-04-08 11:26:46 -07001273
Johannes Berg3779db12010-05-14 06:25:58 -07001274 IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
Wey-Yi Guyf35c0c52011-01-13 17:09:29 -08001275 viftype, vif->addr);
Abhijeet Kolekarcbb6ab92009-04-08 11:26:46 -07001276
Johannes Bergc6baf7f2011-07-23 10:24:47 -07001277 cancel_delayed_work_sync(&priv->hw_roc_disable_work);
1278
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -07001279 mutex_lock(&priv->shrd->mutex);
Johannes Berg47e28f42010-01-20 11:21:06 -08001280
Johannes Bergc6baf7f2011-07-23 10:24:47 -07001281 iwlagn_disable_roc(priv);
1282
Stanislaw Gruszka4bd530f2010-09-30 16:27:35 +02001283 if (!iwl_is_ready_rf(priv)) {
1284 IWL_WARN(priv, "Try to add interface when device not ready\n");
Johannes Bergb55e75e2010-02-17 04:54:08 -08001285 err = -EINVAL;
1286 goto out;
1287 }
1288
Johannes Bergd0fe4782010-08-23 10:46:58 +02001289 for_each_context(priv, tmp) {
1290 u32 possible_modes =
1291 tmp->interface_modes | tmp->exclusive_interface_modes;
1292
1293 if (tmp->vif) {
1294 /* check if this busy context is exclusive */
1295 if (tmp->exclusive_interface_modes &
1296 BIT(tmp->vif->type)) {
1297 err = -EINVAL;
1298 goto out;
1299 }
1300 continue;
1301 }
1302
Wey-Yi Guyf35c0c52011-01-13 17:09:29 -08001303 if (!(possible_modes & BIT(viftype)))
Johannes Bergd0fe4782010-08-23 10:46:58 +02001304 continue;
1305
1306 /* have maybe usable context w/o interface */
1307 ctx = tmp;
1308 break;
1309 }
1310
1311 if (!ctx) {
Johannes Berg47e28f42010-01-20 11:21:06 -08001312 err = -EOPNOTSUPP;
1313 goto out;
Abhijeet Kolekarcbb6ab92009-04-08 11:26:46 -07001314 }
1315
Johannes Bergd0fe4782010-08-23 10:46:58 +02001316 vif_priv->ctx = ctx;
Johannes Berg8bd413e2010-08-23 10:46:40 +02001317 ctx->vif = vif;
Abhijeet Kolekarcbb6ab92009-04-08 11:26:46 -07001318
Johannes Bergd4daaea2010-10-23 09:15:43 -07001319 err = iwl_setup_interface(priv, ctx);
1320 if (!err)
1321 goto out;
Johannes Berg763cc3b2010-09-03 06:32:21 -07001322
Johannes Berg8bd413e2010-08-23 10:46:40 +02001323 ctx->vif = NULL;
Johannes Bergb55e75e2010-02-17 04:54:08 -08001324 priv->iw_mode = NL80211_IFTYPE_STATION;
Johannes Berg47e28f42010-01-20 11:21:06 -08001325 out:
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -07001326 mutex_unlock(&priv->shrd->mutex);
Abhijeet Kolekarcbb6ab92009-04-08 11:26:46 -07001327
1328 IWL_DEBUG_MAC80211(priv, "leave\n");
Johannes Berg47e28f42010-01-20 11:21:06 -08001329 return err;
Abhijeet Kolekarcbb6ab92009-04-08 11:26:46 -07001330}
Abhijeet Kolekarcbb6ab92009-04-08 11:26:46 -07001331
Johannes Bergd4daaea2010-10-23 09:15:43 -07001332static void iwl_teardown_interface(struct iwl_priv *priv,
1333 struct ieee80211_vif *vif,
1334 bool mode_change)
1335{
1336 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
1337
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -07001338 lockdep_assert_held(&priv->shrd->mutex);
Johannes Bergd4daaea2010-10-23 09:15:43 -07001339
1340 if (priv->scan_vif == vif) {
1341 iwl_scan_cancel_timeout(priv, 200);
1342 iwl_force_scan_end(priv);
1343 }
1344
1345 if (!mode_change) {
1346 iwl_set_mode(priv, ctx);
1347 if (!ctx->always_active)
1348 ctx->is_active = false;
1349 }
1350
1351 /*
1352 * When removing the IBSS interface, overwrite the
1353 * BT traffic load with the stored one from the last
1354 * notification, if any. If this is a device that
1355 * doesn't implement this, this has no effect since
1356 * both values are the same and zero.
1357 */
1358 if (vif->type == NL80211_IFTYPE_ADHOC)
Wey-Yi Guy66e863a52010-11-08 14:54:37 -08001359 priv->bt_traffic_load = priv->last_bt_traffic_load;
Johannes Bergd4daaea2010-10-23 09:15:43 -07001360}
1361
Abhijeet Kolekard8052312009-04-08 11:26:47 -07001362void iwl_mac_remove_interface(struct ieee80211_hw *hw,
Johannes Bergb55e75e2010-02-17 04:54:08 -08001363 struct ieee80211_vif *vif)
Abhijeet Kolekard8052312009-04-08 11:26:47 -07001364{
1365 struct iwl_priv *priv = hw->priv;
Johannes Berg246ed352010-08-23 10:46:32 +02001366 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
Abhijeet Kolekard8052312009-04-08 11:26:47 -07001367
1368 IWL_DEBUG_MAC80211(priv, "enter\n");
1369
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -07001370 mutex_lock(&priv->shrd->mutex);
Abhijeet Kolekard8052312009-04-08 11:26:47 -07001371
Johannes Bergd0fe4782010-08-23 10:46:58 +02001372 WARN_ON(ctx->vif != vif);
1373 ctx->vif = NULL;
1374
Johannes Bergd4daaea2010-10-23 09:15:43 -07001375 iwl_teardown_interface(priv, vif, false);
Johannes Berg590799492010-08-23 07:57:00 -07001376
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -07001377 mutex_unlock(&priv->shrd->mutex);
Abhijeet Kolekard8052312009-04-08 11:26:47 -07001378
1379 IWL_DEBUG_MAC80211(priv, "leave\n");
1380
1381}
Abhijeet Kolekard8052312009-04-08 11:26:47 -07001382
Wey-Yi Guy20594eb2009-08-07 15:41:39 -07001383#ifdef CONFIG_IWLWIFI_DEBUGFS
1384
1385#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
1386
1387void iwl_reset_traffic_log(struct iwl_priv *priv)
1388{
1389 priv->tx_traffic_idx = 0;
1390 priv->rx_traffic_idx = 0;
1391 if (priv->tx_traffic)
1392 memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
1393 if (priv->rx_traffic)
1394 memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
1395}
1396
1397int iwl_alloc_traffic_mem(struct iwl_priv *priv)
1398{
1399 u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE;
1400
Emmanuel Grumbach8f470ce2011-08-25 23:10:38 -07001401 if (iwl_get_debug_level(priv->shrd) & IWL_DL_TX) {
Wey-Yi Guy20594eb2009-08-07 15:41:39 -07001402 if (!priv->tx_traffic) {
1403 priv->tx_traffic =
1404 kzalloc(traffic_size, GFP_KERNEL);
1405 if (!priv->tx_traffic)
1406 return -ENOMEM;
1407 }
1408 }
Emmanuel Grumbach8f470ce2011-08-25 23:10:38 -07001409 if (iwl_get_debug_level(priv->shrd) & IWL_DL_RX) {
Wey-Yi Guy20594eb2009-08-07 15:41:39 -07001410 if (!priv->rx_traffic) {
1411 priv->rx_traffic =
1412 kzalloc(traffic_size, GFP_KERNEL);
1413 if (!priv->rx_traffic)
1414 return -ENOMEM;
1415 }
1416 }
1417 iwl_reset_traffic_log(priv);
1418 return 0;
1419}
Wey-Yi Guy20594eb2009-08-07 15:41:39 -07001420
1421void iwl_free_traffic_mem(struct iwl_priv *priv)
1422{
1423 kfree(priv->tx_traffic);
1424 priv->tx_traffic = NULL;
1425
1426 kfree(priv->rx_traffic);
1427 priv->rx_traffic = NULL;
1428}
Wey-Yi Guy20594eb2009-08-07 15:41:39 -07001429
1430void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
1431 u16 length, struct ieee80211_hdr *header)
1432{
1433 __le16 fc;
1434 u16 len;
1435
Emmanuel Grumbach8f470ce2011-08-25 23:10:38 -07001436 if (likely(!(iwl_get_debug_level(priv->shrd) & IWL_DL_TX)))
Wey-Yi Guy20594eb2009-08-07 15:41:39 -07001437 return;
1438
1439 if (!priv->tx_traffic)
1440 return;
1441
1442 fc = header->frame_control;
1443 if (ieee80211_is_data(fc)) {
1444 len = (length > IWL_TRAFFIC_ENTRY_SIZE)
1445 ? IWL_TRAFFIC_ENTRY_SIZE : length;
1446 memcpy((priv->tx_traffic +
1447 (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
1448 header, len);
1449 priv->tx_traffic_idx =
1450 (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
1451 }
1452}
Wey-Yi Guy20594eb2009-08-07 15:41:39 -07001453
1454void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
1455 u16 length, struct ieee80211_hdr *header)
1456{
1457 __le16 fc;
1458 u16 len;
1459
Emmanuel Grumbach8f470ce2011-08-25 23:10:38 -07001460 if (likely(!(iwl_get_debug_level(priv->shrd) & IWL_DL_RX)))
Wey-Yi Guy20594eb2009-08-07 15:41:39 -07001461 return;
1462
1463 if (!priv->rx_traffic)
1464 return;
1465
1466 fc = header->frame_control;
1467 if (ieee80211_is_data(fc)) {
1468 len = (length > IWL_TRAFFIC_ENTRY_SIZE)
1469 ? IWL_TRAFFIC_ENTRY_SIZE : length;
1470 memcpy((priv->rx_traffic +
1471 (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
1472 header, len);
1473 priv->rx_traffic_idx =
1474 (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
1475 }
1476}
Wey-Yi Guy22fdf3c2009-08-07 15:41:40 -07001477
1478const char *get_mgmt_string(int cmd)
1479{
1480 switch (cmd) {
1481 IWL_CMD(MANAGEMENT_ASSOC_REQ);
1482 IWL_CMD(MANAGEMENT_ASSOC_RESP);
1483 IWL_CMD(MANAGEMENT_REASSOC_REQ);
1484 IWL_CMD(MANAGEMENT_REASSOC_RESP);
1485 IWL_CMD(MANAGEMENT_PROBE_REQ);
1486 IWL_CMD(MANAGEMENT_PROBE_RESP);
1487 IWL_CMD(MANAGEMENT_BEACON);
1488 IWL_CMD(MANAGEMENT_ATIM);
1489 IWL_CMD(MANAGEMENT_DISASSOC);
1490 IWL_CMD(MANAGEMENT_AUTH);
1491 IWL_CMD(MANAGEMENT_DEAUTH);
1492 IWL_CMD(MANAGEMENT_ACTION);
1493 default:
1494 return "UNKNOWN";
1495
1496 }
1497}
1498
1499const char *get_ctrl_string(int cmd)
1500{
1501 switch (cmd) {
1502 IWL_CMD(CONTROL_BACK_REQ);
1503 IWL_CMD(CONTROL_BACK);
1504 IWL_CMD(CONTROL_PSPOLL);
1505 IWL_CMD(CONTROL_RTS);
1506 IWL_CMD(CONTROL_CTS);
1507 IWL_CMD(CONTROL_ACK);
1508 IWL_CMD(CONTROL_CFEND);
1509 IWL_CMD(CONTROL_CFENDACK);
1510 default:
1511 return "UNKNOWN";
1512
1513 }
1514}
1515
Wey-Yi Guy7163b8a2009-11-20 12:04:56 -08001516void iwl_clear_traffic_stats(struct iwl_priv *priv)
Wey-Yi Guy22fdf3c2009-08-07 15:41:40 -07001517{
1518 memset(&priv->tx_stats, 0, sizeof(struct traffic_stats));
Wey-Yi Guy22fdf3c2009-08-07 15:41:40 -07001519 memset(&priv->rx_stats, 0, sizeof(struct traffic_stats));
1520}
1521
1522/*
1523 * if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will
1524 * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass.
1525 * Use debugFs to display the rx/rx_statistics
1526 * if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL
1527 * information will be recorded, but DATA pkt still will be recorded
1528 * for the reason of iwl_led.c need to control the led blinking based on
1529 * number of tx and rx data.
1530 *
1531 */
1532void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
1533{
1534 struct traffic_stats *stats;
1535
1536 if (is_tx)
1537 stats = &priv->tx_stats;
1538 else
1539 stats = &priv->rx_stats;
1540
1541 if (ieee80211_is_mgmt(fc)) {
1542 switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
1543 case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
1544 stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
1545 break;
1546 case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
1547 stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
1548 break;
1549 case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
1550 stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
1551 break;
1552 case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
1553 stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
1554 break;
1555 case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
1556 stats->mgmt[MANAGEMENT_PROBE_REQ]++;
1557 break;
1558 case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
1559 stats->mgmt[MANAGEMENT_PROBE_RESP]++;
1560 break;
1561 case cpu_to_le16(IEEE80211_STYPE_BEACON):
1562 stats->mgmt[MANAGEMENT_BEACON]++;
1563 break;
1564 case cpu_to_le16(IEEE80211_STYPE_ATIM):
1565 stats->mgmt[MANAGEMENT_ATIM]++;
1566 break;
1567 case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
1568 stats->mgmt[MANAGEMENT_DISASSOC]++;
1569 break;
1570 case cpu_to_le16(IEEE80211_STYPE_AUTH):
1571 stats->mgmt[MANAGEMENT_AUTH]++;
1572 break;
1573 case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
1574 stats->mgmt[MANAGEMENT_DEAUTH]++;
1575 break;
1576 case cpu_to_le16(IEEE80211_STYPE_ACTION):
1577 stats->mgmt[MANAGEMENT_ACTION]++;
1578 break;
1579 }
1580 } else if (ieee80211_is_ctl(fc)) {
1581 switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
1582 case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
1583 stats->ctrl[CONTROL_BACK_REQ]++;
1584 break;
1585 case cpu_to_le16(IEEE80211_STYPE_BACK):
1586 stats->ctrl[CONTROL_BACK]++;
1587 break;
1588 case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
1589 stats->ctrl[CONTROL_PSPOLL]++;
1590 break;
1591 case cpu_to_le16(IEEE80211_STYPE_RTS):
1592 stats->ctrl[CONTROL_RTS]++;
1593 break;
1594 case cpu_to_le16(IEEE80211_STYPE_CTS):
1595 stats->ctrl[CONTROL_CTS]++;
1596 break;
1597 case cpu_to_le16(IEEE80211_STYPE_ACK):
1598 stats->ctrl[CONTROL_ACK]++;
1599 break;
1600 case cpu_to_le16(IEEE80211_STYPE_CFEND):
1601 stats->ctrl[CONTROL_CFEND]++;
1602 break;
1603 case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
1604 stats->ctrl[CONTROL_CFENDACK]++;
1605 break;
1606 }
1607 } else {
1608 /* data */
1609 stats->data_cnt++;
1610 stats->data_bytes += len;
1611 }
1612}
Wey-Yi Guy20594eb2009-08-07 15:41:39 -07001613#endif
1614
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001615static void iwl_force_rf_reset(struct iwl_priv *priv)
Wey-Yi Guyafbdd692010-01-22 14:22:43 -08001616{
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -07001617 if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
Wey-Yi Guyafbdd692010-01-22 14:22:43 -08001618 return;
1619
Johannes Berg246ed352010-08-23 10:46:32 +02001620 if (!iwl_is_any_associated(priv)) {
Wey-Yi Guyafbdd692010-01-22 14:22:43 -08001621 IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
1622 return;
1623 }
1624 /*
1625 * There is no easy and better way to force reset the radio,
1626 * the only known method is switching channel which will force to
1627 * reset and tune the radio.
1628 * Use internal short scan (single channel) operation to should
1629 * achieve this objective.
1630 * Driver should reset the radio when number of consecutive missed
1631 * beacon, or any other uCode error condition detected.
1632 */
1633 IWL_DEBUG_INFO(priv, "perform radio reset.\n");
1634 iwl_internal_short_hw_scan(priv);
Wey-Yi Guyafbdd692010-01-22 14:22:43 -08001635}
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001636
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001637
Wey-Yi Guyc04f9f22010-06-21 16:52:55 -07001638int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001639{
Wey-Yi Guy8a472da2010-02-18 22:03:06 -08001640 struct iwl_force_reset *force_reset;
1641
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -07001642 if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001643 return -EINVAL;
1644
Wey-Yi Guy8a472da2010-02-18 22:03:06 -08001645 if (mode >= IWL_MAX_FORCE_RESET) {
1646 IWL_DEBUG_INFO(priv, "invalid reset request.\n");
1647 return -EINVAL;
1648 }
1649 force_reset = &priv->force_reset[mode];
1650 force_reset->reset_request_count++;
Wey-Yi Guyc04f9f22010-06-21 16:52:55 -07001651 if (!external) {
1652 if (force_reset->last_force_reset_jiffies &&
1653 time_after(force_reset->last_force_reset_jiffies +
1654 force_reset->reset_duration, jiffies)) {
1655 IWL_DEBUG_INFO(priv, "force reset rejected\n");
1656 force_reset->reset_reject_count++;
1657 return -EAGAIN;
1658 }
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001659 }
Wey-Yi Guy8a472da2010-02-18 22:03:06 -08001660 force_reset->reset_success_count++;
1661 force_reset->last_force_reset_jiffies = jiffies;
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001662 IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode);
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001663 switch (mode) {
1664 case IWL_RF_RESET:
1665 iwl_force_rf_reset(priv);
1666 break;
1667 case IWL_FW_RESET:
Wey-Yi Guyc04f9f22010-06-21 16:52:55 -07001668 /*
1669 * if the request is from external(ex: debugfs),
1670 * then always perform the request in regardless the module
1671 * parameter setting
1672 * if the request is from internal (uCode error or driver
1673 * detect failure), then fw_restart module parameter
1674 * need to be check before performing firmware reload
1675 */
Don Fry9d143e92011-04-20 15:23:57 -07001676 if (!external && !iwlagn_mod_params.restart_fw) {
Wey-Yi Guyc04f9f22010-06-21 16:52:55 -07001677 IWL_DEBUG_INFO(priv, "Cancel firmware reload based on "
1678 "module parameter setting\n");
1679 break;
1680 }
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001681 IWL_ERR(priv, "On demand firmware reload\n");
Johannes Berge6494372011-04-05 09:41:58 -07001682 iwlagn_fw_error(priv, true);
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001683 break;
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001684 }
Wey-Yi Guya93e7972010-02-03 11:47:19 -08001685 return 0;
1686}
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001687
Johannes Bergd4daaea2010-10-23 09:15:43 -07001688int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1689 enum nl80211_iftype newtype, bool newp2p)
1690{
1691 struct iwl_priv *priv = hw->priv;
1692 struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
Johannes Bergebf8dc82011-04-27 05:19:34 -07001693 struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
Johannes Bergd4daaea2010-10-23 09:15:43 -07001694 struct iwl_rxon_context *tmp;
Johannes Berg5306c082011-06-21 08:28:31 -07001695 enum nl80211_iftype newviftype = newtype;
Johannes Bergd4daaea2010-10-23 09:15:43 -07001696 u32 interface_modes;
1697 int err;
1698
1699 newtype = ieee80211_iftype_p2p(newtype, newp2p);
1700
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -07001701 mutex_lock(&priv->shrd->mutex);
Johannes Bergd4daaea2010-10-23 09:15:43 -07001702
Johannes Berga2b76b32011-03-29 06:29:37 -07001703 if (!ctx->vif || !iwl_is_ready_rf(priv)) {
1704 /*
1705 * Huh? But wait ... this can maybe happen when
1706 * we're in the middle of a firmware restart!
1707 */
1708 err = -EBUSY;
1709 goto out;
1710 }
1711
Johannes Bergd4daaea2010-10-23 09:15:43 -07001712 interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
1713
1714 if (!(interface_modes & BIT(newtype))) {
1715 err = -EBUSY;
1716 goto out;
1717 }
1718
Johannes Bergebf8dc82011-04-27 05:19:34 -07001719 /*
1720 * Refuse a change that should be done by moving from the PAN
1721 * context to the BSS context instead, if the BSS context is
1722 * available and can support the new interface type.
1723 */
1724 if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
1725 (bss_ctx->interface_modes & BIT(newtype) ||
1726 bss_ctx->exclusive_interface_modes & BIT(newtype))) {
1727 BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
1728 err = -EBUSY;
1729 goto out;
1730 }
1731
Johannes Bergd4daaea2010-10-23 09:15:43 -07001732 if (ctx->exclusive_interface_modes & BIT(newtype)) {
1733 for_each_context(priv, tmp) {
1734 if (ctx == tmp)
1735 continue;
1736
1737 if (!tmp->vif)
1738 continue;
1739
1740 /*
1741 * The current mode switch would be exclusive, but
1742 * another context is active ... refuse the switch.
1743 */
1744 err = -EBUSY;
1745 goto out;
1746 }
1747 }
1748
1749 /* success */
1750 iwl_teardown_interface(priv, vif, true);
Johannes Berg5306c082011-06-21 08:28:31 -07001751 vif->type = newviftype;
Johannes Berga2b76b32011-03-29 06:29:37 -07001752 vif->p2p = newp2p;
Johannes Bergd4daaea2010-10-23 09:15:43 -07001753 err = iwl_setup_interface(priv, ctx);
1754 WARN_ON(err);
1755 /*
1756 * We've switched internally, but submitting to the
1757 * device may have failed for some reason. Mask this
1758 * error, because otherwise mac80211 will not switch
1759 * (and set the interface type back) and we'll be
1760 * out of sync with it.
1761 */
1762 err = 0;
1763
1764 out:
Emmanuel Grumbach6ac2f832011-08-25 23:10:44 -07001765 mutex_unlock(&priv->shrd->mutex);
Johannes Bergd4daaea2010-10-23 09:15:43 -07001766 return err;
1767}
Johannes Bergd4daaea2010-10-23 09:15:43 -07001768
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001769/*
Stanislaw Gruszka22de94d2010-12-03 15:41:48 +01001770 * On every watchdog tick we check (latest) time stamp. If it does not
1771 * change during timeout period and queue is not empty we reset firmware.
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001772 */
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001773static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
1774{
Stanislaw Gruszka22de94d2010-12-03 15:41:48 +01001775 struct iwl_tx_queue *txq = &priv->txq[cnt];
1776 struct iwl_queue *q = &txq->q;
1777 unsigned long timeout;
1778 int ret;
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001779
Stanislaw Gruszka22de94d2010-12-03 15:41:48 +01001780 if (q->read_ptr == q->write_ptr) {
1781 txq->time_stamp = jiffies;
Wey-Yi Guy7cb1b082010-10-06 08:10:00 -07001782 return 0;
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001783 }
Stanislaw Gruszka22de94d2010-12-03 15:41:48 +01001784
1785 timeout = txq->time_stamp +
1786 msecs_to_jiffies(priv->cfg->base_params->wd_timeout);
1787
1788 if (time_after(jiffies, timeout)) {
1789 IWL_ERR(priv, "Queue %d stuck for %u ms.\n",
1790 q->id, priv->cfg->base_params->wd_timeout);
1791 ret = iwl_force_reset(priv, IWL_FW_RESET, false);
1792 return (ret == -EAGAIN) ? 0 : 1;
1793 }
1794
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001795 return 0;
1796}
1797
Stanislaw Gruszka22de94d2010-12-03 15:41:48 +01001798/*
1799 * Making watchdog tick be a quarter of timeout assure we will
1800 * discover the queue hung between timeout and 1.25*timeout
1801 */
1802#define IWL_WD_TICK(timeout) ((timeout) / 4)
1803
1804/*
1805 * Watchdog timer callback, we check each tx queue for stuck, if if hung
1806 * we reset the firmware. If everything is fine just rearm the timer.
1807 */
1808void iwl_bg_watchdog(unsigned long data)
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001809{
1810 struct iwl_priv *priv = (struct iwl_priv *)data;
1811 int cnt;
Stanislaw Gruszka22de94d2010-12-03 15:41:48 +01001812 unsigned long timeout;
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001813
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -07001814 if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001815 return;
1816
Stanislaw Gruszka22de94d2010-12-03 15:41:48 +01001817 timeout = priv->cfg->base_params->wd_timeout;
1818 if (timeout == 0)
1819 return;
1820
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001821 /* monitor and check for stuck cmd queue */
Emmanuel Grumbachcefeaa52011-08-25 23:10:40 -07001822 if (iwl_check_stuck_queue(priv, priv->shrd->cmd_queue))
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001823 return;
1824
1825 /* monitor and check for other stuck queues */
Johannes Berg246ed352010-08-23 10:46:32 +02001826 if (iwl_is_any_associated(priv)) {
Emmanuel Grumbachd6189122011-08-25 23:10:39 -07001827 for (cnt = 0; cnt < hw_params(priv).max_txq_num; cnt++) {
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001828 /* skip as we already checked the command queue */
Emmanuel Grumbachcefeaa52011-08-25 23:10:40 -07001829 if (cnt == priv->shrd->cmd_queue)
Wey-Yi Guyb74e31a2010-03-01 17:23:50 -08001830 continue;
1831 if (iwl_check_stuck_queue(priv, cnt))
1832 return;
1833 }
1834 }
Wey-Yi Guyafbdd692010-01-22 14:22:43 -08001835
Stanislaw Gruszka22de94d2010-12-03 15:41:48 +01001836 mod_timer(&priv->watchdog, jiffies +
1837 msecs_to_jiffies(IWL_WD_TICK(timeout)));
1838}
Stanislaw Gruszka22de94d2010-12-03 15:41:48 +01001839
1840void iwl_setup_watchdog(struct iwl_priv *priv)
1841{
1842 unsigned int timeout = priv->cfg->base_params->wd_timeout;
1843
Wey-Yi Guy300d0832011-06-25 09:17:41 -07001844 if (timeout && !iwlagn_mod_params.wd_disable)
Stanislaw Gruszka22de94d2010-12-03 15:41:48 +01001845 mod_timer(&priv->watchdog,
1846 jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout)));
1847 else
1848 del_timer(&priv->watchdog);
1849}
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001850
1851/*
1852 * extended beacon time format
1853 * time in usec will be changed into a 32-bit value in extended:internal format
1854 * the extended part is the beacon counts
1855 * the internal part is the time in usec within one beacon interval
1856 */
1857u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval)
1858{
1859 u32 quot;
1860 u32 rem;
1861 u32 interval = beacon_interval * TIME_UNIT;
1862
1863 if (!interval || !usec)
1864 return 0;
1865
1866 quot = (usec / interval) &
1867 (iwl_beacon_time_mask_high(priv,
Emmanuel Grumbachd6189122011-08-25 23:10:39 -07001868 hw_params(priv).beacon_time_tsf_bits) >>
1869 hw_params(priv).beacon_time_tsf_bits);
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001870 rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
Emmanuel Grumbachd6189122011-08-25 23:10:39 -07001871 hw_params(priv).beacon_time_tsf_bits);
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001872
Emmanuel Grumbachd6189122011-08-25 23:10:39 -07001873 return (quot << hw_params(priv).beacon_time_tsf_bits) + rem;
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001874}
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001875
1876/* base is usually what we get from ucode with each received frame,
1877 * the same as HW timer counter counting down
1878 */
1879__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
1880 u32 addon, u32 beacon_interval)
1881{
1882 u32 base_low = base & iwl_beacon_time_mask_low(priv,
Emmanuel Grumbachd6189122011-08-25 23:10:39 -07001883 hw_params(priv).beacon_time_tsf_bits);
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001884 u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
Emmanuel Grumbachd6189122011-08-25 23:10:39 -07001885 hw_params(priv).beacon_time_tsf_bits);
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001886 u32 interval = beacon_interval * TIME_UNIT;
1887 u32 res = (base & iwl_beacon_time_mask_high(priv,
Emmanuel Grumbachd6189122011-08-25 23:10:39 -07001888 hw_params(priv).beacon_time_tsf_bits)) +
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001889 (addon & iwl_beacon_time_mask_high(priv,
Emmanuel Grumbachd6189122011-08-25 23:10:39 -07001890 hw_params(priv).beacon_time_tsf_bits));
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001891
1892 if (base_low > addon_low)
1893 res += base_low - addon_low;
1894 else if (base_low < addon_low) {
1895 res += interval + base_low - addon_low;
Emmanuel Grumbachd6189122011-08-25 23:10:39 -07001896 res += (1 << hw_params(priv).beacon_time_tsf_bits);
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001897 } else
Emmanuel Grumbachd6189122011-08-25 23:10:39 -07001898 res += (1 << hw_params(priv).beacon_time_tsf_bits);
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001899
1900 return cpu_to_le32(res);
1901}
Wey-Yi Guya0ee74c2010-05-06 08:54:10 -07001902
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001903#ifdef CONFIG_PM
1904
Emmanuel Grumbach48d1a212011-05-24 11:39:02 +03001905int iwl_suspend(struct iwl_priv *priv)
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001906{
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001907 /*
1908 * This function is called when system goes into suspend state
1909 * mac80211 will call iwl_mac_stop() from the mac80211 suspend function
1910 * first but since iwl_mac_stop() has no knowledge of who the caller is,
1911 * it will not call apm_ops.stop() to stop the DMA operation.
1912 * Calling apm_ops.stop here to make sure we stop the DMA.
Johannes Bergc8ac61c2011-07-15 13:23:45 -07001913 *
1914 * But of course ... if we have configured WoWLAN then we did other
1915 * things already :-)
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001916 */
Johannes Bergc8ac61c2011-07-15 13:23:45 -07001917 if (!priv->wowlan)
1918 iwl_apm_stop(priv);
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001919
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001920 return 0;
1921}
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001922
Emmanuel Grumbach48d1a212011-05-24 11:39:02 +03001923int iwl_resume(struct iwl_priv *priv)
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001924{
Johannes Berg0ab84cf2010-06-18 01:38:56 -07001925 bool hw_rfkill = false;
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001926
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001927 iwl_enable_interrupts(priv);
1928
Johannes Berg0ab84cf2010-06-18 01:38:56 -07001929 if (!(iwl_read32(priv, CSR_GP_CNTRL) &
1930 CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
1931 hw_rfkill = true;
1932
1933 if (hw_rfkill)
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -07001934 set_bit(STATUS_RF_KILL_HW, &priv->shrd->status);
Johannes Berg0ab84cf2010-06-18 01:38:56 -07001935 else
Emmanuel Grumbach63013ae2011-08-25 23:10:42 -07001936 clear_bit(STATUS_RF_KILL_HW, &priv->shrd->status);
Johannes Berg0ab84cf2010-06-18 01:38:56 -07001937
1938 wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rfkill);
1939
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001940 return 0;
1941}
Wey-Yi Guy6da3a132009-03-26 10:14:08 -07001942
1943#endif /* CONFIG_PM */