iwl-5000.c 13.4 KB
Newer Older
1 2
/******************************************************************************
 *
W
Wey-Yi Guy 已提交
3
 * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 * The full GNU General Public License is included in this distribution in the
 * file called LICENSE.
 *
 * Contact Information:
22
 *  Intel Linux Wireless <ilw@linux.intel.com>
23 24 25 26 27 28 29 30
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *
 *****************************************************************************/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
31
#include <linux/sched.h>
32 33 34 35 36
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>
37
#include <linux/stringify.h>
38 39

#include "iwl-eeprom.h"
40
#include "iwl-dev.h"
41 42
#include "iwl-core.h"
#include "iwl-io.h"
43
#include "iwl-sta.h"
44
#include "iwl-helpers.h"
45
#include "iwl-agn.h"
46
#include "iwl-agn-hw.h"
47
#include "iwl-5000-hw.h"
48
#include "iwl-trans.h"
49
#include "iwl-shared.h"
50
#include "iwl-pci.h"
51

52
/* Highest firmware API version supported */
53
#define IWL5000_UCODE_API_MAX 5
54
#define IWL5150_UCODE_API_MAX 2
55

56 57 58 59 60
/* Lowest firmware API version supported */
#define IWL5000_UCODE_API_MIN 1
#define IWL5150_UCODE_API_MIN 1

#define IWL5000_FW_PRE "iwlwifi-5000-"
61
#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode"
62 63

#define IWL5150_FW_PRE "iwlwifi-5150-"
64
#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode"
65

66
/* NIC configuration for 5000 series */
67
static void iwl5000_nic_config(struct iwl_priv *priv)
68 69 70
{
	unsigned long flags;

71
	iwl_rf_config(priv);
72

73
	spin_lock_irqsave(&priv->shrd->lock, flags);
74

T
Tomas Winkler 已提交
75 76 77 78
	/* W/A : NIC is stuck in a reset state after Early PCIe power off
	 * (PCIe power is lost before PERST# is asserted),
	 * causing ME FW to lose ownership and not being able to obtain it back.
	 */
79
	iwl_set_bits_mask_prph(bus(priv), APMG_PS_CTRL_REG,
T
Tomas Winkler 已提交
80 81 82
				APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
				~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);

W
Wey-Yi Guy 已提交
83

84
	spin_unlock_irqrestore(&priv->shrd->lock, flags);
85 86
}

87
static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
88
	.min_nrg_cck = 100,
89
	.max_nrg_cck = 0, /* not used, set to 0 */
90 91
	.auto_corr_min_ofdm = 90,
	.auto_corr_min_ofdm_mrc = 170,
92 93
	.auto_corr_min_ofdm_x1 = 105,
	.auto_corr_min_ofdm_mrc_x1 = 220,
94 95 96

	.auto_corr_max_ofdm = 120,
	.auto_corr_max_ofdm_mrc = 210,
97 98
	.auto_corr_max_ofdm_x1 = 120,
	.auto_corr_max_ofdm_mrc_x1 = 240,
99 100 101

	.auto_corr_min_cck = 125,
	.auto_corr_max_cck = 200,
102
	.auto_corr_min_cck_mrc = 200,
103
	.auto_corr_max_cck_mrc = 400,
104 105
	.nrg_th_cck = 100,
	.nrg_th_ofdm = 100,
106 107 108 109

	.barker_corr_th_min = 190,
	.barker_corr_th_min_mrc = 390,
	.nrg_th_cca = 62,
110 111
};

112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
	.min_nrg_cck = 95,
	.max_nrg_cck = 0, /* not used, set to 0 */
	.auto_corr_min_ofdm = 90,
	.auto_corr_min_ofdm_mrc = 170,
	.auto_corr_min_ofdm_x1 = 105,
	.auto_corr_min_ofdm_mrc_x1 = 220,

	.auto_corr_max_ofdm = 120,
	.auto_corr_max_ofdm_mrc = 210,
	/* max = min for performance bug in 5150 DSP */
	.auto_corr_max_ofdm_x1 = 105,
	.auto_corr_max_ofdm_mrc_x1 = 220,

	.auto_corr_min_cck = 125,
	.auto_corr_max_cck = 200,
	.auto_corr_min_cck_mrc = 170,
	.auto_corr_max_cck_mrc = 400,
	.nrg_th_cck = 95,
	.nrg_th_ofdm = 95,
132 133 134 135

	.barker_corr_th_min = 190,
	.barker_corr_th_min_mrc = 390,
	.nrg_th_cca = 62,
136 137
};

138
static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
139
{
140
	const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
141
	s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
142 143
			iwl_temp_calib_to_offset(priv);

144
	hw_params(priv).ct_kill_threshold = threshold * volt2temp_coef;
145 146 147 148 149
}

static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
{
	/* want Celsius */
150
	hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
151 152
}

153
static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
154
{
D
Don Fry 已提交
155 156
	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
157
		priv->cfg->base_params->num_of_queues =
D
Don Fry 已提交
158
			iwlagn_mod_params.num_of_queues;
159

160 161
	hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues;
	hw_params(priv).max_stations = IWLAGN_STATION_COUNT;
162
	priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
163

164 165
	hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE;
	hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE;
166

167
	hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
168
					BIT(IEEE80211_BAND_5GHZ);
169

170 171 172 173
	hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
	hw_params(priv).rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
	hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant;
	hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant;
174

175
	iwl5000_set_ct_threshold(priv);
176

177
	/* Set initial sensitivity parameters */
178
	/* Set initial calibration set */
179 180
	hw_params(priv).sens = &iwl5000_sensitivity;
	hw_params(priv).calib_init_cfg =
181 182 183 184 185 186
		BIT(IWL_CALIB_XTAL)		|
		BIT(IWL_CALIB_LO)		|
		BIT(IWL_CALIB_TX_IQ)		|
		BIT(IWL_CALIB_TX_IQ_PERD)	|
		BIT(IWL_CALIB_BASE_BAND);

187
	hw_params(priv).beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
188

189 190 191 192 193
	return 0;
}

static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
{
D
Don Fry 已提交
194 195
	if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
	    iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
196
		priv->cfg->base_params->num_of_queues =
D
Don Fry 已提交
197
			iwlagn_mod_params.num_of_queues;
198

199 200
	hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues;
	hw_params(priv).max_stations = IWLAGN_STATION_COUNT;
201
	priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
202

203 204
	hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE;
	hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE;
205

206
	hw_params(priv).ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
207 208
					BIT(IEEE80211_BAND_5GHZ);

209 210 211 212
	hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
	hw_params(priv).rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
	hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant;
	hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant;
213

214
	iwl5150_set_ct_threshold(priv);
215 216 217

	/* Set initial sensitivity parameters */
	/* Set initial calibration set */
218 219
	hw_params(priv).sens = &iwl5150_sensitivity;
	hw_params(priv).calib_init_cfg =
220 221 222
		BIT(IWL_CALIB_LO)		|
		BIT(IWL_CALIB_TX_IQ)		|
		BIT(IWL_CALIB_BASE_BAND);
223
	if (priv->cfg->need_dc_calib)
224
		hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC);
225

226
	hw_params(priv).beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
227

228 229
	return 0;
}
230

231 232 233 234 235
static void iwl5150_temperature(struct iwl_priv *priv)
{
	u32 vt = 0;
	s32 offset =  iwl_temp_calib_to_offset(priv);

236
	vt = le32_to_cpu(priv->statistics.common.temperature);
237 238 239
	vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
	/* now vt hold the temperature in Kelvin */
	priv->temperature = KELVIN_TO_CELSIUS(vt);
240
	iwl_tt_handler(priv);
241 242
}

243 244
static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
				     struct ieee80211_channel_switch *ch_switch)
245
{
246 247 248 249 250
	/*
	 * MULTI-FIXME
	 * See iwl_mac_channel_switch.
	 */
	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
251 252
	struct iwl5000_channel_switch_cmd cmd;
	const struct iwl_channel_info *ch_info;
253 254 255 256
	u32 switch_time_in_usec, ucode_switch_time;
	u16 ch;
	u32 tsf_low;
	u8 switch_count;
257
	u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
258
	struct ieee80211_vif *vif = ctx->vif;
259 260
	struct iwl_host_cmd hcmd = {
		.id = REPLY_CHANNEL_SWITCH,
261
		.len = { sizeof(cmd), },
262
		.flags = CMD_SYNC,
263
		.data = { &cmd, },
264 265 266
	};

	cmd.band = priv->band == IEEE80211_BAND_2GHZ;
267
	ch = ch_switch->channel->hw_value;
268
	IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
269
		      ctx->active.channel, ch);
270
	cmd.channel = cpu_to_le16(ch);
271 272
	cmd.rxon_flags = ctx->staging.flags;
	cmd.rxon_filter_flags = ctx->staging.filter_flags;
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
	switch_count = ch_switch->count;
	tsf_low = ch_switch->timestamp & 0x0ffffffff;
	/*
	 * calculate the ucode channel switch time
	 * adding TSF as one of the factor for when to switch
	 */
	if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
		if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
		    beacon_interval)) {
			switch_count -= (priv->ucode_beacon_time -
				tsf_low) / beacon_interval;
		} else
			switch_count = 0;
	}
	if (switch_count <= 1)
		cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
	else {
		switch_time_in_usec =
			vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
		ucode_switch_time = iwl_usecs_to_beacons(priv,
							 switch_time_in_usec,
							 beacon_interval);
		cmd.switch_time = iwl_add_beacon_time(priv,
						      priv->ucode_beacon_time,
						      ucode_switch_time,
						      beacon_interval);
	}
	IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
		      cmd.switch_time);
	ch_info = iwl_get_channel_info(priv, priv->band, ch);
303 304 305 306
	if (ch_info)
		cmd.expect_beacon = is_channel_radar(ch_info);
	else {
		IWL_ERR(priv, "invalid channel switch from %u to %u\n",
307
			ctx->active.channel, ch);
308 309 310
		return -EFAULT;
	}

311
	return iwl_trans_send_cmd(trans(priv), &hcmd);
312 313
}

314
static struct iwl_lib_ops iwl5000_lib = {
315
	.set_hw_params = iwl5000_hw_set_hw_params,
316
	.set_channel_switch = iwl5000_hw_channel_switch,
317
	.nic_config = iwl5000_nic_config,
318
	.eeprom_ops = {
319
		.regulatory_bands = {
320 321 322 323 324 325 326
			EEPROM_REG_BAND_1_CHANNELS,
			EEPROM_REG_BAND_2_CHANNELS,
			EEPROM_REG_BAND_3_CHANNELS,
			EEPROM_REG_BAND_4_CHANNELS,
			EEPROM_REG_BAND_5_CHANNELS,
			EEPROM_REG_BAND_24_HT40_CHANNELS,
			EEPROM_REG_BAND_52_HT40_CHANNELS
327
		},
328
	},
329
	.temperature = iwlagn_temperature,
330 331 332
};

static struct iwl_lib_ops iwl5150_lib = {
333
	.set_hw_params = iwl5150_hw_set_hw_params,
334
	.set_channel_switch = iwl5000_hw_channel_switch,
335
	.nic_config = iwl5000_nic_config,
336 337
	.eeprom_ops = {
		.regulatory_bands = {
338 339 340 341 342 343 344
			EEPROM_REG_BAND_1_CHANNELS,
			EEPROM_REG_BAND_2_CHANNELS,
			EEPROM_REG_BAND_3_CHANNELS,
			EEPROM_REG_BAND_4_CHANNELS,
			EEPROM_REG_BAND_5_CHANNELS,
			EEPROM_REG_BAND_24_HT40_CHANNELS,
			EEPROM_REG_BAND_52_HT40_CHANNELS
345 346
		},
	},
347
	.temperature = iwl5150_temperature,
348 349
};

350
static struct iwl_base_params iwl5000_base_params = {
351 352 353
	.eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
	.num_of_queues = IWLAGN_NUM_QUEUES,
	.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
354
	.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
355
	.led_compensation = 51,
356
	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
357
	.chain_noise_scale = 1000,
358
	.wd_timeout = IWL_LONG_WD_TIMEOUT,
W
Wey-Yi Guy 已提交
359
	.max_event_log_size = 512,
360
	.no_idle_support = true,
361
};
362 363 364 365
static struct iwl_ht_params iwl5000_ht_params = {
	.ht_greenfield_support = true,
};

366 367 368 369 370 371
#define IWL_DEVICE_5000						\
	.fw_name_pre = IWL5000_FW_PRE,				\
	.ucode_api_max = IWL5000_UCODE_API_MAX,			\
	.ucode_api_min = IWL5000_UCODE_API_MIN,			\
	.eeprom_ver = EEPROM_5000_EEPROM_VERSION,		\
	.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,	\
372
	.lib = &iwl5000_lib,					\
373 374 375
	.base_params = &iwl5000_base_params,			\
	.led_mode = IWL_LED_BLINK

376 377
struct iwl_cfg iwl5300_agn_cfg = {
	.name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
378
	IWL_DEVICE_5000,
379 380 381
	/* at least EEPROM 0x11A has wrong info */
	.valid_tx_ant = ANT_ABC,	/* .cfg overwrite */
	.valid_rx_ant = ANT_ABC,	/* .cfg overwrite */
382 383
	.ht_params = &iwl5000_ht_params,
};
384

385
struct iwl_cfg iwl5100_bgn_cfg = {
386
	.name = "Intel(R) WiFi Link 5100 BGN",
387
	IWL_DEVICE_5000,
388 389
	.valid_tx_ant = ANT_B,		/* .cfg overwrite */
	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */
390
	.ht_params = &iwl5000_ht_params,
391 392 393
};

struct iwl_cfg iwl5100_abg_cfg = {
394
	.name = "Intel(R) WiFi Link 5100 ABG",
395
	IWL_DEVICE_5000,
396 397
	.valid_tx_ant = ANT_B,		/* .cfg overwrite */
	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */
398 399
};

400
struct iwl_cfg iwl5100_agn_cfg = {
401
	.name = "Intel(R) WiFi Link 5100 AGN",
402
	IWL_DEVICE_5000,
403 404
	.valid_tx_ant = ANT_B,		/* .cfg overwrite */
	.valid_rx_ant = ANT_AB,		/* .cfg overwrite */
405
	.ht_params = &iwl5000_ht_params,
406 407 408
};

struct iwl_cfg iwl5350_agn_cfg = {
409
	.name = "Intel(R) WiMAX/WiFi Link 5350 AGN",
410 411 412
	.fw_name_pre = IWL5000_FW_PRE,
	.ucode_api_max = IWL5000_UCODE_API_MAX,
	.ucode_api_min = IWL5000_UCODE_API_MIN,
413 414
	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
415
	.lib = &iwl5000_lib,
416 417
	.base_params = &iwl5000_base_params,
	.ht_params = &iwl5000_ht_params,
418
	.led_mode = IWL_LED_BLINK,
419
	.internal_wimax_coex = true,
420 421
};

422 423 424 425 426 427
#define IWL_DEVICE_5150						\
	.fw_name_pre = IWL5150_FW_PRE,				\
	.ucode_api_max = IWL5150_UCODE_API_MAX,			\
	.ucode_api_min = IWL5150_UCODE_API_MIN,			\
	.eeprom_ver = EEPROM_5050_EEPROM_VERSION,		\
	.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,	\
428
	.lib = &iwl5150_lib,					\
429 430 431 432 433
	.base_params = &iwl5000_base_params,			\
	.need_dc_calib = true,					\
	.led_mode = IWL_LED_BLINK,				\
	.internal_wimax_coex = true

T
Tomas Winkler 已提交
434
struct iwl_cfg iwl5150_agn_cfg = {
435
	.name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
436
	IWL_DEVICE_5150,
437
	.ht_params = &iwl5000_ht_params,
438

T
Tomas Winkler 已提交
439 440
};

441
struct iwl_cfg iwl5150_abg_cfg = {
442
	.name = "Intel(R) WiMAX/WiFi Link 5150 ABG",
443
	IWL_DEVICE_5150,
T
Tomas Winkler 已提交
444 445
};

446 447
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));