iwl-4965.c 122 KB
Newer Older
1
2
/******************************************************************************
 *
3
 * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 *
 * 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:
 * James P. Ketrenos <ipw2100-admin@linux.intel.com>
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *
 *****************************************************************************/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
Zhu Yi's avatar
Zhu Yi committed
39
#include <asm/unaligned.h>
40

41
#include "iwl-eeprom.h"
42
#include "iwl-4965.h"
43
#include "iwl-core.h"
44
#include "iwl-io.h"
45
#include "iwl-helpers.h"
46
#include "iwl-calib.h"
47

48
49
/* module parameters */
static struct iwl_mod_params iwl4965_mod_params = {
50
	.num_of_queues = IWL4965_MAX_NUM_QUEUES,
51
52
53
54
55
	.enable_qos = 1,
	.amsdu_size_8K = 1,
	/* the rest are 0 by default */
};

56
static void iwl4965_hw_card_show_info(struct iwl_priv *priv);
57

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
				    IWL_RATE_SISO_##s##M_PLCP, \
				    IWL_RATE_MIMO_##s##M_PLCP, \
				    IWL_RATE_##r##M_IEEE,      \
				    IWL_RATE_##ip##M_INDEX,    \
				    IWL_RATE_##in##M_INDEX,    \
				    IWL_RATE_##rp##M_INDEX,    \
				    IWL_RATE_##rn##M_INDEX,    \
				    IWL_RATE_##pp##M_INDEX,    \
				    IWL_RATE_##np##M_INDEX }

/*
 * Parameter order:
 *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
 *
 * If there isn't a valid next or previous rate then INV is used which
 * maps to IWL_RATE_INVALID
 *
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
78
const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = {
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
	IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
	IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
	IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
	IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */
	IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
	IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */
	IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
	IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
	IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
	IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
	IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
	IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
	IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
};

94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#ifdef CONFIG_IWL4965_HT

static const u16 default_tid_to_tx_fifo[] = {
	IWL_TX_FIFO_AC1,
	IWL_TX_FIFO_AC0,
	IWL_TX_FIFO_AC0,
	IWL_TX_FIFO_AC1,
	IWL_TX_FIFO_AC2,
	IWL_TX_FIFO_AC2,
	IWL_TX_FIFO_AC3,
	IWL_TX_FIFO_AC3,
	IWL_TX_FIFO_NONE,
	IWL_TX_FIFO_NONE,
	IWL_TX_FIFO_NONE,
	IWL_TX_FIFO_NONE,
	IWL_TX_FIFO_NONE,
	IWL_TX_FIFO_NONE,
	IWL_TX_FIFO_NONE,
	IWL_TX_FIFO_NONE,
	IWL_TX_FIFO_AC3
};

#endif	/*CONFIG_IWL4965_HT */

118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/* check contents of special bootstrap uCode SRAM */
static int iwl4965_verify_bsm(struct iwl_priv *priv)
{
	__le32 *image = priv->ucode_boot.v_addr;
	u32 len = priv->ucode_boot.len;
	u32 reg;
	u32 val;

	IWL_DEBUG_INFO("Begin verify bsm\n");

	/* verify BSM SRAM contents */
	val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG);
	for (reg = BSM_SRAM_LOWER_BOUND;
	     reg < BSM_SRAM_LOWER_BOUND + len;
	     reg += sizeof(u32), image++) {
		val = iwl_read_prph(priv, reg);
		if (val != le32_to_cpu(*image)) {
			IWL_ERROR("BSM uCode verification failed at "
				  "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
				  BSM_SRAM_LOWER_BOUND,
				  reg - BSM_SRAM_LOWER_BOUND, len,
				  val, le32_to_cpu(*image));
			return -EIO;
		}
	}

	IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");

	return 0;
}

/**
 * iwl4965_load_bsm - Load bootstrap instructions
 *
 * BSM operation:
 *
 * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
 * in special SRAM that does not power down during RFKILL.  When powering back
 * up after power-saving sleeps (or during initial uCode load), the BSM loads
 * the bootstrap program into the on-board processor, and starts it.
 *
 * The bootstrap program loads (via DMA) instructions and data for a new
 * program from host DRAM locations indicated by the host driver in the
 * BSM_DRAM_* registers.  Once the new program is loaded, it starts
 * automatically.
 *
 * When initializing the NIC, the host driver points the BSM to the
 * "initialize" uCode image.  This uCode sets up some internal data, then
 * notifies host via "initialize alive" that it is complete.
 *
 * The host then replaces the BSM_DRAM_* pointer values to point to the
 * normal runtime uCode instructions and a backup uCode data cache buffer
 * (filled initially with starting data values for the on-board processor),
 * then triggers the "initialize" uCode to load and launch the runtime uCode,
 * which begins normal operation.
 *
 * When doing a power-save shutdown, runtime uCode saves data SRAM into
 * the backup data cache in DRAM before SRAM is powered down.
 *
 * When powering back up, the BSM loads the bootstrap program.  This reloads
 * the runtime uCode instructions and the backup data cache into SRAM,
 * and re-launches the runtime uCode from where it left off.
 */
static int iwl4965_load_bsm(struct iwl_priv *priv)
{
	__le32 *image = priv->ucode_boot.v_addr;
	u32 len = priv->ucode_boot.len;
	dma_addr_t pinst;
	dma_addr_t pdata;
	u32 inst_len;
	u32 data_len;
	int i;
	u32 done;
	u32 reg_offset;
	int ret;

	IWL_DEBUG_INFO("Begin load bsm\n");

	/* make sure bootstrap program is no larger than BSM's SRAM size */
	if (len > IWL_MAX_BSM_SIZE)
		return -EINVAL;

	/* Tell bootstrap uCode where to find the "Initialize" uCode
	 *   in host DRAM ... host DRAM physical address bits 35:4 for 4965.
	 * NOTE:  iwl4965_initialize_alive_start() will replace these values,
	 *        after the "initialize" uCode has run, to point to
	 *        runtime/protocol instructions and backup data cache. */
	pinst = priv->ucode_init.p_addr >> 4;
	pdata = priv->ucode_init_data.p_addr >> 4;
	inst_len = priv->ucode_init.len;
	data_len = priv->ucode_init_data.len;

	ret = iwl_grab_nic_access(priv);
	if (ret)
		return ret;

	iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
	iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
	iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
	iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);

	/* Fill BSM memory with bootstrap instructions */
	for (reg_offset = BSM_SRAM_LOWER_BOUND;
	     reg_offset < BSM_SRAM_LOWER_BOUND + len;
	     reg_offset += sizeof(u32), image++)
		_iwl_write_prph(priv, reg_offset, le32_to_cpu(*image));

	ret = iwl4965_verify_bsm(priv);
	if (ret) {
		iwl_release_nic_access(priv);
		return ret;
	}

	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
	iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
	iwl_write_prph(priv, BSM_WR_MEM_DST_REG, RTC_INST_LOWER_BOUND);
	iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));

	/* Load bootstrap code into instruction SRAM now,
	 *   to prepare to load "initialize" uCode */
	iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START);

	/* Wait for load of bootstrap uCode to finish */
	for (i = 0; i < 100; i++) {
		done = iwl_read_prph(priv, BSM_WR_CTRL_REG);
		if (!(done & BSM_WR_CTRL_REG_BIT_START))
			break;
		udelay(10);
	}
	if (i < 100)
		IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
	else {
		IWL_ERROR("BSM write did not complete!\n");
		return -EIO;
	}

	/* Enable future boot loads whenever power management unit triggers it
	 *   (e.g. when powering back up after power-save shutdown) */
	iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN);

	iwl_release_nic_access(priv);

	return 0;
}

263
264
265
266
267
static int iwl4965_init_drv(struct iwl_priv *priv)
{
	int ret;
	int i;

268
	priv->antenna = (enum iwl4965_antenna)priv->cfg->mod_params->antenna;
269
270
271
272
273
274
275
276
277
	priv->retry_rate = 1;
	priv->ibss_beacon = NULL;

	spin_lock_init(&priv->lock);
	spin_lock_init(&priv->power_data.lock);
	spin_lock_init(&priv->sta_lock);
	spin_lock_init(&priv->hcmd_lock);
	spin_lock_init(&priv->lq_mngr.lock);

278
279
280
281
282
283
284
285
286
287
288
289
	priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
					sizeof(struct iwl4965_shared),
					&priv->shared_phys);

	if (!priv->shared_virt) {
		ret = -ENOMEM;
		goto err;
	}

	memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared));


290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
		INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);

	INIT_LIST_HEAD(&priv->free_frames);

	mutex_init(&priv->mutex);

	/* Clear the driver's (not device's) station table */
	iwlcore_clear_stations_table(priv);

	priv->data_retry_limit = -1;
	priv->ieee_channels = NULL;
	priv->ieee_rates = NULL;
	priv->band = IEEE80211_BAND_2GHZ;

	priv->iw_mode = IEEE80211_IF_TYPE_STA;

	priv->use_ant_b_for_management_frame = 1; /* start with ant B */
	priv->valid_antenna = 0x7;	/* assume all 3 connected */
	priv->ps_mode = IWL_MIMO_PS_NONE;

	/* Choose which receivers/antennas to use */
	iwl4965_set_rxon_chain(priv);

	iwlcore_reset_qos(priv);

	priv->qos_data.qos_active = 0;
	priv->qos_data.qos_cap.val = 0;

	iwlcore_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);

	priv->rates_mask = IWL_RATES_MASK;
	/* If power management is turned on, default to AC mode */
	priv->power_mode = IWL_POWER_AC;
	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;

	ret = iwl_init_channel_map(priv);
	if (ret) {
		IWL_ERROR("initializing regulatory failed: %d\n", ret);
		goto err;
	}

	ret = iwl4965_init_geos(priv);
	if (ret) {
		IWL_ERROR("initializing geos failed: %d\n", ret);
		goto err_free_channel_map;
	}

	ret = ieee80211_register_hw(priv->hw);
	if (ret) {
		IWL_ERROR("Failed to register network device (error %d)\n",
				ret);
		goto err_free_geos;
	}

	priv->hw->conf.beacon_int = 100;
	priv->mac80211_registered = 1;

	return 0;

err_free_geos:
	iwl4965_free_geos(priv);
err_free_channel_map:
	iwl_free_channel_map(priv);
err:
	return ret;
}

358
359
360
361
362
363
static int is_fat_channel(__le32 rxon_flags)
{
	return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
		(rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK);
}

364
static u8 is_single_stream(struct iwl_priv *priv)
365
{
366
#ifdef CONFIG_IWL4965_HT
367
368
	if (!priv->current_ht_config.is_ht ||
	    (priv->current_ht_config.supp_mcs_set[1] == 0) ||
369
370
371
372
	    (priv->ps_mode == IWL_MIMO_PS_STATIC))
		return 1;
#else
	return 1;
373
#endif	/*CONFIG_IWL4965_HT */
374
375
376
	return 0;
}

377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags)
{
	int idx = 0;

	/* 4965 HT rate format */
	if (rate_n_flags & RATE_MCS_HT_MSK) {
		idx = (rate_n_flags & 0xff);

		if (idx >= IWL_RATE_MIMO_6M_PLCP)
			idx = idx - IWL_RATE_MIMO_6M_PLCP;

		idx += IWL_FIRST_OFDM_RATE;
		/* skip 9M not supported in ht*/
		if (idx >= IWL_RATE_9M_INDEX)
			idx += 1;
		if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE))
			return idx;

	/* 4965 legacy rate format, search for match in table */
	} else {
		for (idx = 0; idx < ARRAY_SIZE(iwl4965_rates); idx++)
			if (iwl4965_rates[idx].plcp == (rate_n_flags & 0xFF))
				return idx;
	}

	return -1;
}

405
406
407
/**
 * translate ucode response to mac80211 tx status control values
 */
408
void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
409
410
411
412
413
				  struct ieee80211_tx_control *control)
{
	int rate_index;

	control->antenna_sel_tx =
414
		((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS);
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
	if (rate_n_flags & RATE_MCS_HT_MSK)
		control->flags |= IEEE80211_TXCTL_OFDM_HT;
	if (rate_n_flags & RATE_MCS_GF_MSK)
		control->flags |= IEEE80211_TXCTL_GREEN_FIELD;
	if (rate_n_flags & RATE_MCS_FAT_MSK)
		control->flags |= IEEE80211_TXCTL_40_MHZ_WIDTH;
	if (rate_n_flags & RATE_MCS_DUP_MSK)
		control->flags |= IEEE80211_TXCTL_DUP_DATA;
	if (rate_n_flags & RATE_MCS_SGI_MSK)
		control->flags |= IEEE80211_TXCTL_SHORT_GI;
	/* since iwl4965_hwrate_to_plcp_idx is band indifferent, we always use
	 * IEEE80211_BAND_2GHZ band as it contains all the rates */
	rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags);
	if (rate_index == -1)
		control->tx_rate = NULL;
	else
		control->tx_rate =
			&priv->bands[IEEE80211_BAND_2GHZ].bitrates[rate_index];
}
434

435
436
437
438
439
440
/*
 * Determine how many receiver/antenna chains to use.
 * More provides better reception via diversity.  Fewer saves power.
 * MIMO (dual stream) requires at least 2, but works better with 3.
 * This does not determine *which* chains to use, just how many.
 */
441
static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv,
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
					u8 *idle_state, u8 *rx_state)
{
	u8 is_single = is_single_stream(priv);
	u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;

	/* # of Rx chains to use when expecting MIMO. */
	if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
		*rx_state = 2;
	else
		*rx_state = 3;

	/* # Rx chains when idling and maybe trying to save power */
	switch (priv->ps_mode) {
	case IWL_MIMO_PS_STATIC:
	case IWL_MIMO_PS_DYNAMIC:
		*idle_state = (is_cam) ? 2 : 1;
		break;
	case IWL_MIMO_PS_NONE:
		*idle_state = (is_cam) ? *rx_state : 1;
		break;
	default:
		*idle_state = 1;
		break;
	}

	return 0;
}

470
int iwl4965_hw_rxq_stop(struct iwl_priv *priv)
471
472
473
474
475
{
	int rc;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);
476
	rc = iwl_grab_nic_access(priv);
477
478
479
480
481
	if (rc) {
		spin_unlock_irqrestore(&priv->lock, flags);
		return rc;
	}

482
	/* stop Rx DMA */
483
484
	iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
	rc = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
485
486
487
488
				     (1 << 24), 1000);
	if (rc < 0)
		IWL_ERROR("Can't stop Rx DMA.\n");

489
	iwl_release_nic_access(priv);
490
491
492
493
494
	spin_unlock_irqrestore(&priv->lock, flags);

	return 0;
}

495
int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
496
{
497
	int ret;
498
499
500
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);
501
	ret = iwl_grab_nic_access(priv);
502
	if (ret) {
503
		spin_unlock_irqrestore(&priv->lock, flags);
504
		return ret;
505
506
	}

Tomas Winkler's avatar
Tomas Winkler committed
507
	if (src == IWL_PWR_SRC_VAUX) {
508
		u32 val;
509
		ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
Tomas Winkler's avatar
Tomas Winkler committed
510
					    &val);
511

Tomas Winkler's avatar
Tomas Winkler committed
512
		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
513
			iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
Tomas Winkler's avatar
Tomas Winkler committed
514
515
516
517
					       APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
					       ~APMG_PS_CTRL_MSK_PWR_SRC);
		}
	} else {
518
		iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
Tomas Winkler's avatar
Tomas Winkler committed
519
520
521
				       APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
				       ~APMG_PS_CTRL_MSK_PWR_SRC);
	}
522

523
	iwl_release_nic_access(priv);
524
525
	spin_unlock_irqrestore(&priv->lock, flags);

526
	return ret;
527
528
}

529
static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
530
{
531
	int ret;
532
	unsigned long flags;
533
	unsigned int rb_size;
534
535

	spin_lock_irqsave(&priv->lock, flags);
536
537
	ret = iwl_grab_nic_access(priv);
	if (ret) {
538
		spin_unlock_irqrestore(&priv->lock, flags);
539
		return ret;
540
541
	}

542
	if (priv->cfg->mod_params->amsdu_size_8K)
543
544
545
546
		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
	else
		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;

547
	/* Stop Rx DMA */
548
	iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
549

550
	/* Reset driver's Rx queue write index */
551
	iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
552
553

	/* Tell device where to find RBD circular buffer in DRAM */
554
555
	iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
			   rxq->dma_addr >> 8);
556

557
	/* Tell device where in DRAM to update its Rx status */
558
	iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
559
560
			   (priv->shared_phys +
			    offsetof(struct iwl4965_shared, rb_closed)) >> 4);
561

562
	/* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
563
564
565
566
	iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
			   FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
			   FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
			   rb_size |
567
			     /* 0x10 << 4 | */
568
			   (RX_QUEUE_SIZE_LOG <<
569
570
571
			      FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));

	/*
572
	 * iwl_write32(priv,CSR_INT_COAL_REG,0);
573
574
	 */

575
	iwl_release_nic_access(priv);
576
577
578
579
580
	spin_unlock_irqrestore(&priv->lock, flags);

	return 0;
}

581
/* Tell 4965 where to find the "keep warm" buffer */
582
static int iwl4965_kw_init(struct iwl_priv *priv)
583
584
585
586
587
{
	unsigned long flags;
	int rc;

	spin_lock_irqsave(&priv->lock, flags);
588
	rc = iwl_grab_nic_access(priv);
589
590
591
	if (rc)
		goto out;

592
	iwl_write_direct32(priv, IWL_FH_KW_MEM_ADDR_REG,
593
			     priv->kw.dma_addr >> 4);
594
	iwl_release_nic_access(priv);
595
596
597
598
599
out:
	spin_unlock_irqrestore(&priv->lock, flags);
	return rc;
}

600
static int iwl4965_kw_alloc(struct iwl_priv *priv)
601
602
{
	struct pci_dev *dev = priv->pci_dev;
Christoph Hellwig's avatar
Christoph Hellwig committed
603
	struct iwl4965_kw *kw = &priv->kw;
604
605
606
607
608
609
610
611
612

	kw->size = IWL4965_KW_SIZE;	/* TBW need set somewhere else */
	kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
	if (!kw->v_addr)
		return -ENOMEM;

	return 0;
}

613
614
615
/**
 * iwl4965_kw_free - Free the "keep warm" buffer
 */
616
static void iwl4965_kw_free(struct iwl_priv *priv)
617
618
{
	struct pci_dev *dev = priv->pci_dev;
Christoph Hellwig's avatar
Christoph Hellwig committed
619
	struct iwl4965_kw *kw = &priv->kw;
620
621
622
623
624
625
626
627
628
629
630
631
632
633

	if (kw->v_addr) {
		pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
		memset(kw, 0, sizeof(*kw));
	}
}

/**
 * iwl4965_txq_ctx_reset - Reset TX queue context
 * Destroys all DMA structures and initialise them again
 *
 * @param priv
 * @return error code
 */
634
static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
635
636
637
638
639
640
641
{
	int rc = 0;
	int txq_id, slots_num;
	unsigned long flags;

	iwl4965_kw_free(priv);

642
	/* Free all tx/cmd queues and keep-warm buffer */
Christoph Hellwig's avatar
Christoph Hellwig committed
643
	iwl4965_hw_txq_ctx_free(priv);
644

645
	/* Alloc keep-warm buffer */
646
647
648
649
650
651
652
653
	rc = iwl4965_kw_alloc(priv);
	if (rc) {
		IWL_ERROR("Keep Warm allocation failed");
		goto error_kw;
	}

	spin_lock_irqsave(&priv->lock, flags);

654
	rc = iwl_grab_nic_access(priv);
655
656
657
658
659
660
	if (unlikely(rc)) {
		IWL_ERROR("TX reset failed");
		spin_unlock_irqrestore(&priv->lock, flags);
		goto error_reset;
	}

661
	/* Turn off all Tx DMA channels */
Tomas Winkler's avatar
Tomas Winkler committed
662
	iwl_write_prph(priv, IWL49_SCD_TXFACT, 0);
663
	iwl_release_nic_access(priv);
664
665
	spin_unlock_irqrestore(&priv->lock, flags);

666
	/* Tell 4965 where to find the keep-warm buffer */
667
668
669
670
671
672
	rc = iwl4965_kw_init(priv);
	if (rc) {
		IWL_ERROR("kw_init failed\n");
		goto error_reset;
	}

673
674
	/* Alloc and init all (default 16) Tx queues,
	 * including the command queue (#4) */
Tomas Winkler's avatar
Tomas Winkler committed
675
	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
676
677
		slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
Christoph Hellwig's avatar
Christoph Hellwig committed
678
		rc = iwl4965_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
679
680
681
682
683
684
685
686
687
688
				       txq_id);
		if (rc) {
			IWL_ERROR("Tx %d queue init failed\n", txq_id);
			goto error;
		}
	}

	return rc;

 error:
Christoph Hellwig's avatar
Christoph Hellwig committed
689
	iwl4965_hw_txq_ctx_free(priv);
690
691
692
693
694
695
 error_reset:
	iwl4965_kw_free(priv);
 error_kw:
	return rc;
}

696
int iwl4965_hw_nic_init(struct iwl_priv *priv)
697
698
699
{
	int rc;
	unsigned long flags;
Christoph Hellwig's avatar
Christoph Hellwig committed
700
	struct iwl4965_rx_queue *rxq = &priv->rxq;
701
702
703
704
	u8 rev_id;
	u32 val;
	u8 val_link;

Christoph Hellwig's avatar
Christoph Hellwig committed
705
	iwl4965_power_init_handle(priv);
706
707
708
709

	/* nic_init */
	spin_lock_irqsave(&priv->lock, flags);

710
	iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
711
712
		    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);

713
714
	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
	rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
715
716
717
718
719
720
721
722
			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
	if (rc < 0) {
		spin_unlock_irqrestore(&priv->lock, flags);
		IWL_DEBUG_INFO("Failed to init the card\n");
		return rc;
	}

723
	rc = iwl_grab_nic_access(priv);
724
725
726
727
728
	if (rc) {
		spin_unlock_irqrestore(&priv->lock, flags);
		return rc;
	}

729
	iwl_read_prph(priv, APMG_CLK_CTRL_REG);
730

731
732
733
	iwl_write_prph(priv, APMG_CLK_CTRL_REG,
			APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
	iwl_read_prph(priv, APMG_CLK_CTRL_REG);
734
735
736

	udelay(20);

737
738
	iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
				APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
739

740
741
	iwl_release_nic_access(priv);
	iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
742
743
744
745
746
747
748
749
750
	spin_unlock_irqrestore(&priv->lock, flags);

	/* Determine HW type */
	rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
	if (rc)
		return rc;

	IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id);

Tomas Winkler's avatar
Tomas Winkler committed
751
752
	rc = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);

753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
	spin_lock_irqsave(&priv->lock, flags);

	if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) {
		pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val);
		/* Enable No Snoop field */
		pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8,
				       val & ~(1 << 11));
	}

	spin_unlock_irqrestore(&priv->lock, flags);

	if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) {
		IWL_ERROR("Older EEPROM detected!  Aborting.\n");
		return -EINVAL;
	}

	pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);

	/* disable L1 entry -- workaround for pre-B1 */
	pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02);

	spin_lock_irqsave(&priv->lock, flags);

	/* set CSR_HW_CONFIG_REG for uCode use */

778
779
780
781
	iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
		    CSR49_HW_IF_CONFIG_REG_BIT_4965_R |
		    CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI |
		    CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI);
782

783
	rc = iwl_grab_nic_access(priv);
784
785
786
787
788
789
	if (rc < 0) {
		spin_unlock_irqrestore(&priv->lock, flags);
		IWL_DEBUG_INFO("Failed to init the card\n");
		return rc;
	}

790
791
	iwl_read_prph(priv, APMG_PS_CTRL_REG);
	iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
792
	udelay(5);
793
	iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
794

795
	iwl_release_nic_access(priv);
796
797
	spin_unlock_irqrestore(&priv->lock, flags);

Christoph Hellwig's avatar
Christoph Hellwig committed
798
	iwl4965_hw_card_show_info(priv);
799
800
801
802
803

	/* end nic_init */

	/* Allocate the RX queue, or reset if it is already allocated */
	if (!rxq->bd) {
Christoph Hellwig's avatar
Christoph Hellwig committed
804
		rc = iwl4965_rx_queue_alloc(priv);
805
806
807
808
809
		if (rc) {
			IWL_ERROR("Unable to initialize Rx queue\n");
			return -ENOMEM;
		}
	} else
Christoph Hellwig's avatar
Christoph Hellwig committed
810
		iwl4965_rx_queue_reset(priv, rxq);
811

Christoph Hellwig's avatar
Christoph Hellwig committed
812
	iwl4965_rx_replenish(priv);
813
814
815
816
817
818

	iwl4965_rx_init(priv, rxq);

	spin_lock_irqsave(&priv->lock, flags);

	rxq->need_update = 1;
Christoph Hellwig's avatar
Christoph Hellwig committed
819
	iwl4965_rx_queue_update_write_ptr(priv, rxq);
820
821

	spin_unlock_irqrestore(&priv->lock, flags);
822
823

	/* Allocate and init all Tx and Command queues */
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
	rc = iwl4965_txq_ctx_reset(priv);
	if (rc)
		return rc;

	if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
		IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n");

	if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
		IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n");

	set_bit(STATUS_INIT, &priv->status);

	return 0;
}

839
int iwl4965_hw_nic_stop_master(struct iwl_priv *priv)
840
841
842
843
844
845
846
847
{
	int rc = 0;
	u32 reg_val;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);

	/* set stop master bit */
848
	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
849

850
	reg_val = iwl_read32(priv, CSR_GP_CNTRL);
851
852
853
854
855
856

	if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
	    (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
		IWL_DEBUG_INFO("Card in power save, master is already "
			       "stopped\n");
	else {
857
		rc = iwl_poll_bit(priv, CSR_RESET,
858
859
860
861
862
863
864
865
866
867
868
869
870
871
				  CSR_RESET_REG_FLAG_MASTER_DISABLED,
				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
		if (rc < 0) {
			spin_unlock_irqrestore(&priv->lock, flags);
			return rc;
		}
	}

	spin_unlock_irqrestore(&priv->lock, flags);
	IWL_DEBUG_INFO("stop master\n");

	return rc;
}

872
873
874
/**
 * iwl4965_hw_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory
 */
875
void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv)
876
877
878
879
880
{

	int txq_id;
	unsigned long flags;

881
	/* Stop each Tx DMA channel, and wait for it to be idle */
Tomas Winkler's avatar
Tomas Winkler committed
882
	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
883
		spin_lock_irqsave(&priv->lock, flags);
884
		if (iwl_grab_nic_access(priv)) {
885
886
887
888
			spin_unlock_irqrestore(&priv->lock, flags);
			continue;
		}

889
890
891
892
893
894
		iwl_write_direct32(priv,
				   IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0);
		iwl_poll_direct_bit(priv, IWL_FH_TSSR_TX_STATUS_REG,
				    IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
				    (txq_id), 200);
		iwl_release_nic_access(priv);
895
896
897
		spin_unlock_irqrestore(&priv->lock, flags);
	}

898
	/* Deallocate memory for all Tx queues */
Christoph Hellwig's avatar
Christoph Hellwig committed
899
	iwl4965_hw_txq_ctx_free(priv);
900
901
}

902
int iwl4965_hw_nic_reset(struct iwl_priv *priv)
903
904
905
906
{
	int rc = 0;
	unsigned long flags;

Christoph Hellwig's avatar
Christoph Hellwig committed
907
	iwl4965_hw_nic_stop_master(priv);
908
909
910

	spin_lock_irqsave(&priv->lock, flags);

911
	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
912
913
914

	udelay(10);

915
916
	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
	rc = iwl_poll_bit(priv, CSR_RESET,
917
918
919
920
921
			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);

	udelay(10);

922
	rc = iwl_grab_nic_access(priv);
923
	if (!rc) {
924
925
926
		iwl_write_prph(priv, APMG_CLK_EN_REG,
				APMG_CLK_VAL_DMA_CLK_RQT |
				APMG_CLK_VAL_BSM_CLK_RQT);
927
928
929

		udelay(10);

930
931
		iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
					APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
932

933
		iwl_release_nic_access(priv);
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
	}

	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
	wake_up_interruptible(&priv->wait_command_queue);

	spin_unlock_irqrestore(&priv->lock, flags);

	return rc;

}

#define REG_RECALIB_PERIOD (60)

/**
 * iwl4965_bg_statistics_periodic - Timer callback to queue statistics
 *
950
 * This callback is provided in order to send a statistics request.
951
952
953
954
 *
 * This timer function is continually reset to execute within
 * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
 * was received.  We need to ensure we receive the statistics in order
955
 * to update the temperature used for calibrating the TXPOWER.
956
957
958
 */
static void iwl4965_bg_statistics_periodic(unsigned long data)
{
959
	struct iwl_priv *priv = (struct iwl_priv *)data;
960
961
962
963

	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
		return;

964
	iwl_send_statistics_request(priv, CMD_ASYNC);
965
966
967
968
969
}

#define CT_LIMIT_CONST		259
#define TM_CT_KILL_THRESHOLD	110

970
void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
971
{
Christoph Hellwig's avatar
Christoph Hellwig committed
972
	struct iwl4965_ct_kill_config cmd;
973
974
975
976
	u32 R1, R2, R3;
	u32 temp_th;
	u32 crit_temperature;
	unsigned long flags;
977
	int ret = 0;
978
979

	spin_lock_irqsave(&priv->lock, flags);
980
	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
		    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
	spin_unlock_irqrestore(&priv->lock, flags);

	if (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) {
		R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
		R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
		R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
	} else {
		R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]);
		R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]);
		R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]);
	}

	temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD);

	crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2;
	cmd.critical_temperature_R =  cpu_to_le32(crit_temperature);
998
999
1000
	ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
			       sizeof(cmd), &cmd);
	if (ret)
For faster browsing, not all history is shown. View entire blame