3945.c 75.8 KB
Newer Older
Z
Zhu Yi 已提交
1 2
/******************************************************************************
 *
3
 * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
Z
Zhu Yi 已提交
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>
Z
Zhu Yi 已提交
23 24 25 26 27 28 29
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *
 *****************************************************************************/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
30
#include <linux/slab.h>
Z
Zhu Yi 已提交
31 32 33
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
34
#include <linux/sched.h>
Z
Zhu Yi 已提交
35 36 37 38
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
Z
Zhu Yi 已提交
39 40
#include <asm/unaligned.h>
#include <net/mac80211.h>
Z
Zhu Yi 已提交
41

42
#include "common.h"
43
#include "3945.h"
Z
Zhu Yi 已提交
44

45 46 47 48 49
/* Send led command */
static int il3945_send_led_cmd(struct il_priv *il,
				struct il_led_cmd *led_cmd)
{
	struct il_host_cmd cmd = {
50
		.id = C_LEDS,
51 52 53 54 55 56 57 58 59 60 61 62 63
		.len = sizeof(struct il_led_cmd),
		.data = led_cmd,
		.flags = CMD_ASYNC,
		.callback = NULL,
	};

	return il_send_cmd(il, &cmd);
}

const struct il_led_ops il3945_led_ops = {
	.cmd = il3945_send_led_cmd,
};

S
Stanislaw Gruszka 已提交
64
#define IL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
S
Stanislaw Gruszka 已提交
65
	[RATE_##r##M_IDX] = { RATE_##r##M_PLCP,   \
S
Stanislaw Gruszka 已提交
66
				    RATE_##r##M_IEEE,   \
S
Stanislaw Gruszka 已提交
67 68 69 70 71 72
				    RATE_##ip##M_IDX, \
				    RATE_##in##M_IDX, \
				    RATE_##rp##M_IDX, \
				    RATE_##rn##M_IDX, \
				    RATE_##pp##M_IDX, \
				    RATE_##np##M_IDX, \
S
Stanislaw Gruszka 已提交
73 74
				    RATE_##r##M_IDX_TBL, \
				    RATE_##ip##M_IDX_TBL }
Z
Zhu Yi 已提交
75 76 77 78 79 80

/*
 * Parameter order:
 *   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
S
Stanislaw Gruszka 已提交
81
 * maps to RATE_INVALID
Z
Zhu Yi 已提交
82 83
 *
 */
S
Stanislaw Gruszka 已提交
84
const struct il3945_rate_info il3945_rates[RATE_COUNT_3945] = {
S
Stanislaw Gruszka 已提交
85 86 87 88 89 90 91 92 93 94 95 96
	IL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2),    /*  1mbps */
	IL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5),          /*  2mbps */
	IL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
	IL_DECLARE_RATE_INFO(11, 9, 12, 5, 12, 5, 18),      /* 11mbps */
	IL_DECLARE_RATE_INFO(6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
	IL_DECLARE_RATE_INFO(9, 6, 11, 5, 11, 5, 11),       /*  9mbps */
	IL_DECLARE_RATE_INFO(12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
	IL_DECLARE_RATE_INFO(18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
	IL_DECLARE_RATE_INFO(24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
	IL_DECLARE_RATE_INFO(36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
	IL_DECLARE_RATE_INFO(48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
	IL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */
Z
Zhu Yi 已提交
97 98
};

S
Stanislaw Gruszka 已提交
99
static inline u8 il3945_get_prev_ieee_rate(u8 rate_idx)
100
{
S
Stanislaw Gruszka 已提交
101
	u8 rate = il3945_rates[rate_idx].prev_ieee;
102

S
Stanislaw Gruszka 已提交
103
	if (rate == RATE_INVALID)
S
Stanislaw Gruszka 已提交
104
		rate = rate_idx;
105 106 107
	return rate;
}

S
Stanislaw Gruszka 已提交
108 109 110
/* 1 = enable the il3945_disable_events() function */
#define IL_EVT_DISABLE (0)
#define IL_EVT_DISABLE_SIZE (1532/32)
Z
Zhu Yi 已提交
111 112

/**
S
Stanislaw Gruszka 已提交
113
 * il3945_disable_events - Disable selected events in uCode event log
Z
Zhu Yi 已提交
114 115 116 117 118 119
 *
 * Disable an event by writing "1"s into "disable"
 *   bitmap in SRAM.  Bit position corresponds to Event # (id/type).
 *   Default values of 0 enable uCode events to be logged.
 * Use for only special debugging.  This function is just a placeholder as-is,
 *   you'll need to provide the special bits! ...
S
Stanislaw Gruszka 已提交
120
 *   ... and set IL_EVT_DISABLE to 1. */
S
Stanislaw Gruszka 已提交
121
void il3945_disable_events(struct il_priv *il)
Z
Zhu Yi 已提交
122 123 124 125 126
{
	int i;
	u32 base;		/* SRAM address of event log header */
	u32 disable_ptr;	/* SRAM address of event-disable bitmap array */
	u32 array_size;		/* # of u32 entries in array */
S
Stanislaw Gruszka 已提交
127
	static const u32 evt_disable[IL_EVT_DISABLE_SIZE] = {
Z
Zhu Yi 已提交
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
		0x00000000,	/*   31 -    0  Event id numbers */
		0x00000000,	/*   63 -   32 */
		0x00000000,	/*   95 -   64 */
		0x00000000,	/*  127 -   96 */
		0x00000000,	/*  159 -  128 */
		0x00000000,	/*  191 -  160 */
		0x00000000,	/*  223 -  192 */
		0x00000000,	/*  255 -  224 */
		0x00000000,	/*  287 -  256 */
		0x00000000,	/*  319 -  288 */
		0x00000000,	/*  351 -  320 */
		0x00000000,	/*  383 -  352 */
		0x00000000,	/*  415 -  384 */
		0x00000000,	/*  447 -  416 */
		0x00000000,	/*  479 -  448 */
		0x00000000,	/*  511 -  480 */
		0x00000000,	/*  543 -  512 */
		0x00000000,	/*  575 -  544 */
		0x00000000,	/*  607 -  576 */
		0x00000000,	/*  639 -  608 */
		0x00000000,	/*  671 -  640 */
		0x00000000,	/*  703 -  672 */
		0x00000000,	/*  735 -  704 */
		0x00000000,	/*  767 -  736 */
		0x00000000,	/*  799 -  768 */
		0x00000000,	/*  831 -  800 */
		0x00000000,	/*  863 -  832 */
		0x00000000,	/*  895 -  864 */
		0x00000000,	/*  927 -  896 */
		0x00000000,	/*  959 -  928 */
		0x00000000,	/*  991 -  960 */
		0x00000000,	/* 1023 -  992 */
		0x00000000,	/* 1055 - 1024 */
		0x00000000,	/* 1087 - 1056 */
		0x00000000,	/* 1119 - 1088 */
		0x00000000,	/* 1151 - 1120 */
		0x00000000,	/* 1183 - 1152 */
		0x00000000,	/* 1215 - 1184 */
		0x00000000,	/* 1247 - 1216 */
		0x00000000,	/* 1279 - 1248 */
		0x00000000,	/* 1311 - 1280 */
		0x00000000,	/* 1343 - 1312 */
		0x00000000,	/* 1375 - 1344 */
		0x00000000,	/* 1407 - 1376 */
		0x00000000,	/* 1439 - 1408 */
		0x00000000,	/* 1471 - 1440 */
		0x00000000,	/* 1503 - 1472 */
	};

S
Stanislaw Gruszka 已提交
177
	base = le32_to_cpu(il->card_alive.log_event_table_ptr);
S
Stanislaw Gruszka 已提交
178
	if (!il3945_hw_valid_rtc_data_addr(base)) {
179
		IL_ERR("Invalid event log pointer 0x%08X\n", base);
Z
Zhu Yi 已提交
180 181 182
		return;
	}

S
Stanislaw Gruszka 已提交
183 184
	disable_ptr = il_read_targ_mem(il, base + (4 * sizeof(u32)));
	array_size = il_read_targ_mem(il, base + (5 * sizeof(u32)));
Z
Zhu Yi 已提交
185

186
	if (IL_EVT_DISABLE && array_size == IL_EVT_DISABLE_SIZE) {
187
		D_INFO("Disabling selected uCode log events at 0x%x\n",
Z
Zhu Yi 已提交
188
			       disable_ptr);
S
Stanislaw Gruszka 已提交
189
		for (i = 0; i < IL_EVT_DISABLE_SIZE; i++)
S
Stanislaw Gruszka 已提交
190
			il_write_targ_mem(il,
191 192
					   disable_ptr + (i * sizeof(u32)),
					   evt_disable[i]);
Z
Zhu Yi 已提交
193 194

	} else {
195 196 197
		D_INFO("Selected uCode log events may be disabled\n");
		D_INFO("  by writing \"1\"s into disable bitmap\n");
		D_INFO("  in SRAM at 0x%x, size %d u32s\n",
Z
Zhu Yi 已提交
198 199 200 201 202
			       disable_ptr, array_size);
	}

}

S
Stanislaw Gruszka 已提交
203
static int il3945_hwrate_to_plcp_idx(u8 plcp)
204 205 206
{
	int idx;

S
Stanislaw Gruszka 已提交
207
	for (idx = 0; idx < RATE_COUNT_3945; idx++)
S
Stanislaw Gruszka 已提交
208
		if (il3945_rates[idx].plcp == plcp)
209 210 211 212
			return idx;
	return -1;
}

213
#ifdef CONFIG_IWLEGACY_DEBUG
214
#define TX_STATUS_ENTRY(x) case TX_3945_STATUS_FAIL_ ## x: return #x
215

S
Stanislaw Gruszka 已提交
216
static const char *il3945_get_tx_fail_reason(u32 status)
217 218
{
	switch (status & TX_STATUS_MSK) {
219
	case TX_3945_STATUS_SUCCESS:
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
		return "SUCCESS";
		TX_STATUS_ENTRY(SHORT_LIMIT);
		TX_STATUS_ENTRY(LONG_LIMIT);
		TX_STATUS_ENTRY(FIFO_UNDERRUN);
		TX_STATUS_ENTRY(MGMNT_ABORT);
		TX_STATUS_ENTRY(NEXT_FRAG);
		TX_STATUS_ENTRY(LIFE_EXPIRE);
		TX_STATUS_ENTRY(DEST_PS);
		TX_STATUS_ENTRY(ABORTED);
		TX_STATUS_ENTRY(BT_RETRY);
		TX_STATUS_ENTRY(STA_INVALID);
		TX_STATUS_ENTRY(FRAG_DROPPED);
		TX_STATUS_ENTRY(TID_DISABLE);
		TX_STATUS_ENTRY(FRAME_FLUSHED);
		TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
		TX_STATUS_ENTRY(TX_LOCKED);
		TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
	}

	return "UNKNOWN";
}
#else
S
Stanislaw Gruszka 已提交
242
static inline const char *il3945_get_tx_fail_reason(u32 status)
243 244 245 246 247
{
	return "";
}
#endif

248 249 250 251 252
/*
 * get ieee prev rate from rate scale table.
 * for A and B mode we need to overright prev
 * value
 */
S
Stanislaw Gruszka 已提交
253
int il3945_rs_next_rate(struct il_priv *il, int rate)
254
{
S
Stanislaw Gruszka 已提交
255
	int next_rate = il3945_get_prev_ieee_rate(rate);
256

S
Stanislaw Gruszka 已提交
257
	switch (il->band) {
258
	case IEEE80211_BAND_5GHZ:
S
Stanislaw Gruszka 已提交
259 260 261 262
		if (rate == RATE_12M_IDX)
			next_rate = RATE_9M_IDX;
		else if (rate == RATE_6M_IDX)
			next_rate = RATE_6M_IDX;
263
		break;
264
	case IEEE80211_BAND_2GHZ:
S
Stanislaw Gruszka 已提交
265
		if (!(il->_3945.sta_supp_rates & IL_OFDM_RATES_MASK) &&
266
		    il_is_associated(il)) {
S
Stanislaw Gruszka 已提交
267 268
			if (rate == RATE_11M_IDX)
				next_rate = RATE_5M_IDX;
269
		}
270
		break;
271

272 273 274 275 276 277 278
	default:
		break;
	}

	return next_rate;
}

279 280

/**
S
Stanislaw Gruszka 已提交
281
 * il3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
282
 *
S
Stanislaw Gruszka 已提交
283
 * When FW advances 'R' idx, all entries between old and new 'R' idx
284 285 286
 * need to be reclaimed. As result, some free space forms. If there is
 * enough free space (> low mark), wake the stack that feeds us.
 */
S
Stanislaw Gruszka 已提交
287
static void il3945_tx_queue_reclaim(struct il_priv *il,
S
Stanislaw Gruszka 已提交
288
				     int txq_id, int idx)
289
{
S
Stanislaw Gruszka 已提交
290
	struct il_tx_queue *txq = &il->txq[txq_id];
S
Stanislaw Gruszka 已提交
291 292
	struct il_queue *q = &txq->q;
	struct il_tx_info *tx_info;
293

294
	BUG_ON(txq_id == IL39_CMD_QUEUE_NUM);
295

S
Stanislaw Gruszka 已提交
296 297
	for (idx = il_queue_inc_wrap(idx, q->n_bd);
		q->read_ptr != idx;
S
Stanislaw Gruszka 已提交
298
		q->read_ptr = il_queue_inc_wrap(q->read_ptr, q->n_bd)) {
299 300

		tx_info = &txq->txb[txq->q.read_ptr];
S
Stanislaw Gruszka 已提交
301
		ieee80211_tx_status_irqsafe(il->hw, tx_info->skb);
302
		tx_info->skb = NULL;
S
Stanislaw Gruszka 已提交
303
		il->cfg->ops->lib->txq_free_tfd(il, txq);
304 305
	}

306
	if (il_queue_space(q) > q->low_mark && txq_id >= 0 &&
307
	    txq_id != IL39_CMD_QUEUE_NUM && il->mac80211_registered)
S
Stanislaw Gruszka 已提交
308
		il_wake_queue(il, txq);
309 310 311
}

/**
S
Stanislaw Gruszka 已提交
312
 * il3945_hdl_tx - Handle Tx response
313
 */
S
Stanislaw Gruszka 已提交
314
static void il3945_hdl_tx(struct il_priv *il,
315
				struct il_rx_buf *rxb)
316
{
317
	struct il_rx_pkt *pkt = rxb_addr(rxb);
318 319
	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
	int txq_id = SEQ_TO_QUEUE(sequence);
S
Stanislaw Gruszka 已提交
320
	int idx = SEQ_TO_IDX(sequence);
S
Stanislaw Gruszka 已提交
321
	struct il_tx_queue *txq = &il->txq[txq_id];
322
	struct ieee80211_tx_info *info;
S
Stanislaw Gruszka 已提交
323
	struct il3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
324 325
	u32  status = le32_to_cpu(tx_resp->status);
	int rate_idx;
326
	int fail;
327

S
Stanislaw Gruszka 已提交
328 329
	if (idx >= txq->q.n_bd || il_queue_used(&txq->q, idx) == 0) {
		IL_ERR("Read idx for DMA queue txq_id (%d) idx %d "
330
			  "is out of range [0-%d] %d %d\n", txq_id,
S
Stanislaw Gruszka 已提交
331
			  idx, txq->q.n_bd, txq->q.write_ptr,
332 333 334 335
			  txq->q.read_ptr);
		return;
	}

336
	txq->time_stamp = jiffies;
337
	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
338 339 340
	ieee80211_tx_info_clear_status(info);

	/* Fill the MRR chain with some info about on-chip retransmissions */
S
Stanislaw Gruszka 已提交
341
	rate_idx = il3945_hwrate_to_plcp_idx(tx_resp->rate);
342
	if (info->band == IEEE80211_BAND_5GHZ)
S
Stanislaw Gruszka 已提交
343
		rate_idx -= IL_FIRST_OFDM_RATE;
344 345

	fail = tx_resp->failure_frame;
346 347 348

	info->status.rates[0].idx = rate_idx;
	info->status.rates[0].count = fail + 1; /* add final attempt */
349 350

	/* tx_status->rts_retry_count = tx_resp->failure_rts; */
351 352
	info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
				IEEE80211_TX_STAT_ACK : 0;
353

354
	D_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
S
Stanislaw Gruszka 已提交
355
			txq_id, il3945_get_tx_fail_reason(status), status,
356 357
			tx_resp->rate, tx_resp->failure_frame);

S
Stanislaw Gruszka 已提交
358 359
	D_TX_REPLY("Tx queue reclaim %d\n", idx);
	il3945_tx_queue_reclaim(il, txq_id, idx);
360

J
Johannes Berg 已提交
361
	if (status & TX_ABORT_REQUIRED_MSK)
362
		IL_ERR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
363 364 365 366
}



Z
Zhu Yi 已提交
367 368 369 370 371 372 373
/*****************************************************************************
 *
 * Intel PRO/Wireless 3945ABG/BG Network Connection
 *
 *  RX handler implementations
 *
 *****************************************************************************/
374
#ifdef CONFIG_IWLEGACY_DEBUGFS
S
Stanislaw Gruszka 已提交
375
static void il3945_accumulative_stats(struct il_priv *il,
A
Abhijeet Kolekar 已提交
376 377 378 379 380 381 382
					    __le32 *stats)
{
	int i;
	__le32 *prev_stats;
	u32 *accum_stats;
	u32 *delta, *max_delta;

S
Stanislaw Gruszka 已提交
383 384 385
	prev_stats = (__le32 *)&il->_3945.stats;
	accum_stats = (u32 *)&il->_3945.accum_stats;
	delta = (u32 *)&il->_3945.delta_stats;
S
Stanislaw Gruszka 已提交
386
	max_delta = (u32 *)&il->_3945.max_delta;
A
Abhijeet Kolekar 已提交
387

S
Stanislaw Gruszka 已提交
388
	for (i = sizeof(__le32); i < sizeof(struct il3945_notif_stats);
A
Abhijeet Kolekar 已提交
389 390 391 392 393 394 395 396 397 398 399
	     i += sizeof(__le32), stats++, prev_stats++, delta++,
	     max_delta++, accum_stats++) {
		if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
			*delta = (le32_to_cpu(*stats) -
				le32_to_cpu(*prev_stats));
			*accum_stats += *delta;
			if (*delta > *max_delta)
				*max_delta = *delta;
		}
	}

S
Stanislaw Gruszka 已提交
400 401 402 403 404
	/* reset accumulative stats for "no-counter" type stats */
	il->_3945.accum_stats.general.temperature =
		il->_3945.stats.general.temperature;
	il->_3945.accum_stats.general.ttl_timestamp =
		il->_3945.stats.general.ttl_timestamp;
A
Abhijeet Kolekar 已提交
405 406
}
#endif
Z
Zhu Yi 已提交
407

408
void il3945_hdl_stats(struct il_priv *il,
409
		struct il_rx_buf *rxb)
Z
Zhu Yi 已提交
410
{
411
	struct il_rx_pkt *pkt = rxb_addr(rxb);
A
Abhijeet Kolekar 已提交
412

413
	D_RX("Statistics notification received (%d vs %d).\n",
S
Stanislaw Gruszka 已提交
414
		     (int)sizeof(struct il3945_notif_stats),
415
		     le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK);
416
#ifdef CONFIG_IWLEGACY_DEBUGFS
S
Stanislaw Gruszka 已提交
417
	il3945_accumulative_stats(il, (__le32 *)&pkt->u.raw);
A
Abhijeet Kolekar 已提交
418
#endif
Z
Zhu Yi 已提交
419

S
Stanislaw Gruszka 已提交
420
	memcpy(&il->_3945.stats, pkt->u.raw, sizeof(il->_3945.stats));
Z
Zhu Yi 已提交
421 422
}

423
void il3945_hdl_c_stats(struct il_priv *il,
424
			      struct il_rx_buf *rxb)
A
Abhijeet Kolekar 已提交
425
{
426
	struct il_rx_pkt *pkt = rxb_addr(rxb);
A
Abhijeet Kolekar 已提交
427 428
	__le32 *flag = (__le32 *)&pkt->u.raw;

S
Stanislaw Gruszka 已提交
429
	if (le32_to_cpu(*flag) & UCODE_STATS_CLEAR_MSK) {
430
#ifdef CONFIG_IWLEGACY_DEBUGFS
S
Stanislaw Gruszka 已提交
431 432 433 434
		memset(&il->_3945.accum_stats, 0,
			sizeof(struct il3945_notif_stats));
		memset(&il->_3945.delta_stats, 0,
			sizeof(struct il3945_notif_stats));
S
Stanislaw Gruszka 已提交
435
		memset(&il->_3945.max_delta, 0,
S
Stanislaw Gruszka 已提交
436
			sizeof(struct il3945_notif_stats));
A
Abhijeet Kolekar 已提交
437
#endif
438
		D_RX("Statistics have been cleared\n");
A
Abhijeet Kolekar 已提交
439
	}
440
	il3945_hdl_stats(il, rxb);
A
Abhijeet Kolekar 已提交
441 442 443
}


444 445 446 447 448 449
/******************************************************************************
 *
 * Misc. internal state and helper functions
 *
 ******************************************************************************/

S
Stanislaw Gruszka 已提交
450
/* This is necessary only for a number of stats, see the caller. */
S
Stanislaw Gruszka 已提交
451
static int il3945_is_network_packet(struct il_priv *il,
452 453 454 455
		struct ieee80211_hdr *header)
{
	/* Filter incoming packets to determine if they are targeted toward
	 * this network, discarding packets coming from ourselves */
S
Stanislaw Gruszka 已提交
456
	switch (il->iw_mode) {
457
	case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source    | BSSID */
458
		/* packets to our IBSS update information */
S
Stanislaw Gruszka 已提交
459
		return !compare_ether_addr(header->addr3, il->bssid);
460
	case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */
461
		/* packets to our IBSS update information */
S
Stanislaw Gruszka 已提交
462
		return !compare_ether_addr(header->addr2, il->bssid);
463 464 465 466
	default:
		return 1;
	}
}
467

S
Stanislaw Gruszka 已提交
468
static void il3945_pass_packet_to_mac80211(struct il_priv *il,
469
				   struct il_rx_buf *rxb,
Z
Zhu Yi 已提交
470
				   struct ieee80211_rx_status *stats)
Z
Zhu Yi 已提交
471
{
472
	struct il_rx_pkt *pkt = rxb_addr(rxb);
S
Stanislaw Gruszka 已提交
473 474 475
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IL_RX_DATA(pkt);
	struct il3945_rx_frame_hdr *rx_hdr = IL_RX_HDR(pkt);
	struct il3945_rx_frame_end *rx_end = IL_RX_END(pkt);
Z
Zhu Yi 已提交
476 477
	u16 len = le16_to_cpu(rx_hdr->len);
	struct sk_buff *skb;
478
	__le16 fc = hdr->frame_control;
Z
Zhu Yi 已提交
479 480

	/* We received data from the HW, so stop the watchdog */
481
	if (unlikely(len + IL39_RX_FRAME_SIZE >
S
Stanislaw Gruszka 已提交
482
		     PAGE_SIZE << il->hw_params.rx_page_order)) {
483
		D_DROP("Corruption detected!\n");
Z
Zhu Yi 已提交
484 485 486 487
		return;
	}

	/* We only process data packets if the interface is open */
S
Stanislaw Gruszka 已提交
488
	if (unlikely(!il->is_open)) {
489
		D_DROP(
490
			"Dropping packet while interface is not open.\n");
Z
Zhu Yi 已提交
491 492 493
		return;
	}

494
	skb = dev_alloc_skb(128);
Z
Zhu Yi 已提交
495
	if (!skb) {
496
		IL_ERR("dev_alloc_skb failed\n");
Z
Zhu Yi 已提交
497 498
		return;
	}
Z
Zhu Yi 已提交
499

S
Stanislaw Gruszka 已提交
500
	if (!il3945_mod_params.sw_crypto)
S
Stanislaw Gruszka 已提交
501
		il_set_decrypted_flag(il,
Z
Zhu Yi 已提交
502
				       (struct ieee80211_hdr *)rxb_addr(rxb),
Z
Zhu Yi 已提交
503 504
				       le32_to_cpu(rx_end->status), stats);

Z
Zhu Yi 已提交
505 506 507
	skb_add_rx_frag(skb, 0, rxb->page,
			(void *)rx_hdr->payload - (void *)pkt, len);

S
Stanislaw Gruszka 已提交
508
	il_update_stats(il, false, fc, len);
Z
Zhu Yi 已提交
509 510
	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));

S
Stanislaw Gruszka 已提交
511 512
	ieee80211_rx(il->hw, skb);
	il->alloc_rxb_page--;
Z
Zhu Yi 已提交
513
	rxb->page = NULL;
Z
Zhu Yi 已提交
514 515
}

S
Stanislaw Gruszka 已提交
516
#define IL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
517

S
Stanislaw Gruszka 已提交
518
static void il3945_hdl_rx(struct il_priv *il,
519
				struct il_rx_buf *rxb)
Z
Zhu Yi 已提交
520
{
521 522
	struct ieee80211_hdr *header;
	struct ieee80211_rx_status rx_status;
523
	struct il_rx_pkt *pkt = rxb_addr(rxb);
S
Stanislaw Gruszka 已提交
524 525 526
	struct il3945_rx_frame_stats *rx_stats = IL_RX_STATS(pkt);
	struct il3945_rx_frame_hdr *rx_hdr = IL_RX_HDR(pkt);
	struct il3945_rx_frame_end *rx_end = IL_RX_END(pkt);
527 528
	u16 rx_stats_sig_avg __maybe_unused = le16_to_cpu(rx_stats->sig_avg);
	u16 rx_stats_noise_diff __maybe_unused = le16_to_cpu(rx_stats->noise_diff);
Z
Zhu Yi 已提交
529
	u8 network_packet;
530 531 532 533 534

	rx_status.flag = 0;
	rx_status.mactime = le64_to_cpu(rx_end->timestamp);
	rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
535 536 537
	rx_status.freq =
		ieee80211_channel_to_frequency(le16_to_cpu(rx_hdr->channel),
					       rx_status.band);
538

S
Stanislaw Gruszka 已提交
539
	rx_status.rate_idx = il3945_hwrate_to_plcp_idx(rx_hdr->rate);
540
	if (rx_status.band == IEEE80211_BAND_5GHZ)
S
Stanislaw Gruszka 已提交
541
		rx_status.rate_idx -= IL_FIRST_OFDM_RATE;
Z
Zhu Yi 已提交
542

R
Reinette Chatre 已提交
543
	rx_status.antenna = (le16_to_cpu(rx_hdr->phy_flags) &
544 545 546 547 548 549
					RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;

	/* set the preamble flag if appropriate */
	if (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
		rx_status.flag |= RX_FLAG_SHORTPRE;

Z
Zhu Yi 已提交
550
	if ((unlikely(rx_stats->phy_count > 20))) {
551
		D_DROP("dsp size out of range [0,20]: %d/n",
552
				rx_stats->phy_count);
Z
Zhu Yi 已提交
553 554 555
		return;
	}

556 557
	if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR) ||
	    !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
558
		D_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status);
Z
Zhu Yi 已提交
559 560 561
		return;
	}

562

Z
Zhu Yi 已提交
563 564

	/* Convert 3945's rssi indicator to dBm */
565
	rx_status.signal = rx_stats->rssi - IL39_RSSI_OFFSET;
Z
Zhu Yi 已提交
566

567
	D_STATS("Rssi %d sig_avg %d noise_diff %d\n",
J
Johannes Berg 已提交
568 569
			rx_status.signal, rx_stats_sig_avg,
			rx_stats_noise_diff);
Z
Zhu Yi 已提交
570

S
Stanislaw Gruszka 已提交
571
	header = (struct ieee80211_hdr *)IL_RX_DATA(pkt);
Z
Zhu Yi 已提交
572

S
Stanislaw Gruszka 已提交
573
	network_packet = il3945_is_network_packet(il, header);
Z
Zhu Yi 已提交
574

575
	D_STATS("[%c] %d RSSI:%d Signal:%u, Rate:%u\n",
576 577
			      network_packet ? '*' : ' ',
			      le16_to_cpu(rx_hdr->channel),
578
			      rx_status.signal, rx_status.signal,
J
Johannes Berg 已提交
579
			      rx_status.rate_idx);
Z
Zhu Yi 已提交
580

S
Stanislaw Gruszka 已提交
581
	il_dbg_log_rx_data_frame(il, le16_to_cpu(rx_hdr->len),
582
						header);
Z
Zhu Yi 已提交
583 584

	if (network_packet) {
S
Stanislaw Gruszka 已提交
585
		il->_3945.last_beacon_time =
586
			le32_to_cpu(rx_end->beacon_timestamp);
S
Stanislaw Gruszka 已提交
587 588
		il->_3945.last_tsf = le64_to_cpu(rx_end->timestamp);
		il->_3945.last_rx_rssi = rx_status.signal;
Z
Zhu Yi 已提交
589 590
	}

S
Stanislaw Gruszka 已提交
591
	il3945_pass_packet_to_mac80211(il, rxb, &rx_status);
Z
Zhu Yi 已提交
592 593
}

S
Stanislaw Gruszka 已提交
594
int il3945_hw_txq_attach_buf_to_tfd(struct il_priv *il,
S
Stanislaw Gruszka 已提交
595
				     struct il_tx_queue *txq,
596
				     dma_addr_t addr, u16 len, u8 reset, u8 pad)
Z
Zhu Yi 已提交
597 598
{
	int count;
S
Stanislaw Gruszka 已提交
599 600
	struct il_queue *q;
	struct il3945_tfd *tfd, *tfd_tmp;
601 602

	q = &txq->q;
S
Stanislaw Gruszka 已提交
603
	tfd_tmp = (struct il3945_tfd *)txq->tfds;
604
	tfd = &tfd_tmp[q->write_ptr];
605 606 607

	if (reset)
		memset(tfd, 0, sizeof(*tfd));
Z
Zhu Yi 已提交
608 609 610

	count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags));

611
	if (count >= NUM_TFD_CHUNKS || count < 0) {
612
		IL_ERR("Error can not send more than %d chunks\n",
Z
Zhu Yi 已提交
613 614 615 616
			  NUM_TFD_CHUNKS);
		return -EINVAL;
	}

W
Winkler, Tomas 已提交
617 618
	tfd->tbs[count].addr = cpu_to_le32(addr);
	tfd->tbs[count].len = cpu_to_le32(len);
Z
Zhu Yi 已提交
619 620 621 622 623 624 625 626 627 628

	count++;

	tfd->control_flags = cpu_to_le32(TFD_CTL_COUNT_SET(count) |
					 TFD_CTL_PAD_SET(pad));

	return 0;
}

/**
S
Stanislaw Gruszka 已提交
629
 * il3945_hw_txq_free_tfd - Free one TFD, those at idx [txq->q.read_ptr]
Z
Zhu Yi 已提交
630
 *
S
Stanislaw Gruszka 已提交
631
 * Does NOT advance any idxes
Z
Zhu Yi 已提交
632
 */
S
Stanislaw Gruszka 已提交
633
void il3945_hw_txq_free_tfd(struct il_priv *il, struct il_tx_queue *txq)
Z
Zhu Yi 已提交
634
{
S
Stanislaw Gruszka 已提交
635
	struct il3945_tfd *tfd_tmp = (struct il3945_tfd *)txq->tfds;
S
Stanislaw Gruszka 已提交
636 637
	int idx = txq->q.read_ptr;
	struct il3945_tfd *tfd = &tfd_tmp[idx];
S
Stanislaw Gruszka 已提交
638
	struct pci_dev *dev = il->pci_dev;
Z
Zhu Yi 已提交
639 640 641 642
	int i;
	int counter;

	/* sanity check */
W
Winkler, Tomas 已提交
643
	counter = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags));
Z
Zhu Yi 已提交
644
	if (counter > NUM_TFD_CHUNKS) {
645
		IL_ERR("Too many chunks: %i\n", counter);
Z
Zhu Yi 已提交
646
		/* @todo issue fatal error, it is quite serious situation */
647
		return;
Z
Zhu Yi 已提交
648 649
	}

650 651 652
	/* Unmap tx_cmd */
	if (counter)
		pci_unmap_single(dev,
S
Stanislaw Gruszka 已提交
653 654
				dma_unmap_addr(&txq->meta[idx], mapping),
				dma_unmap_len(&txq->meta[idx], len),
655 656
				PCI_DMA_TODEVICE);

Z
Zhu Yi 已提交
657 658
	/* unmap chunks if any */

659
	for (i = 1; i < counter; i++)
W
Winkler, Tomas 已提交
660 661
		pci_unmap_single(dev, le32_to_cpu(tfd->tbs[i].addr),
			 le32_to_cpu(tfd->tbs[i].len), PCI_DMA_TODEVICE);
J
Johannes Berg 已提交
662

663 664 665
	/* free SKB */
	if (txq->txb) {
		struct sk_buff *skb;
J
Johannes Berg 已提交
666

667 668 669 670 671 672
		skb = txq->txb[txq->q.read_ptr].skb;

		/* can be called from irqs-disabled context */
		if (skb) {
			dev_kfree_skb_any(skb);
			txq->txb[txq->q.read_ptr].skb = NULL;
Z
Zhu Yi 已提交
673 674 675 676 677
		}
	}
}

/**
S
Stanislaw Gruszka 已提交
678
 * il3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
Z
Zhu Yi 已提交
679 680
 *
*/
S
Stanislaw Gruszka 已提交
681
void il3945_hw_build_tx_cmd_rate(struct il_priv *il,
S
Stanislaw Gruszka 已提交
682
				  struct il_device_cmd *cmd,
J
Johannes Berg 已提交
683 684 685
				  struct ieee80211_tx_info *info,
				  struct ieee80211_hdr *hdr,
				  int sta_id, int tx_id)
Z
Zhu Yi 已提交
686
{
S
Stanislaw Gruszka 已提交
687
	u16 hw_value = ieee80211_get_tx_rate(il->hw, info)->hw_value;
S
Stanislaw Gruszka 已提交
688
	u16 rate_idx = min(hw_value & 0xffff, RATE_COUNT_3945);
Z
Zhu Yi 已提交
689 690 691 692 693
	u16 rate_mask;
	int rate;
	u8 rts_retry_limit;
	u8 data_retry_limit;
	__le32 tx_flags;
694
	__le16 fc = hdr->frame_control;
S
Stanislaw Gruszka 已提交
695
	struct il3945_tx_cmd *tx_cmd = (struct il3945_tx_cmd *)cmd->cmd.payload;
Z
Zhu Yi 已提交
696

S
Stanislaw Gruszka 已提交
697
	rate = il3945_rates[rate_idx].plcp;
A
Abhijeet Kolekar 已提交
698
	tx_flags = tx_cmd->tx_flags;
Z
Zhu Yi 已提交
699 700

	/* We need to figure out how to get the sta->supp_rates while
701
	 * in this running context */
S
Stanislaw Gruszka 已提交
702
	rate_mask = RATES_MASK_3945;
A
Abhijeet Kolekar 已提交
703 704 705 706 707

	/* Set retry limit on DATA packets and Probe Responses*/
	if (ieee80211_is_probe_resp(fc))
		data_retry_limit = 3;
	else
S
Stanislaw Gruszka 已提交
708
		data_retry_limit = IL_DEFAULT_TX_RETRY;
A
Abhijeet Kolekar 已提交
709 710
	tx_cmd->data_retry_limit = data_retry_limit;

711
	if (tx_id >= IL39_CMD_QUEUE_NUM)
Z
Zhu Yi 已提交
712 713 714 715
		rts_retry_limit = 3;
	else
		rts_retry_limit = 7;

A
Abhijeet Kolekar 已提交
716 717 718
	if (data_retry_limit < rts_retry_limit)
		rts_retry_limit = data_retry_limit;
	tx_cmd->rts_retry_limit = rts_retry_limit;
Z
Zhu Yi 已提交
719

A
Abhijeet Kolekar 已提交
720 721
	tx_cmd->rate = rate;
	tx_cmd->tx_flags = tx_flags;
Z
Zhu Yi 已提交
722 723

	/* OFDM */
A
Abhijeet Kolekar 已提交
724
	tx_cmd->supp_rates[0] =
S
Stanislaw Gruszka 已提交
725
	   ((rate_mask & IL_OFDM_RATES_MASK) >> IL_FIRST_OFDM_RATE) & 0xFF;
Z
Zhu Yi 已提交
726 727

	/* CCK */
A
Abhijeet Kolekar 已提交
728
	tx_cmd->supp_rates[1] = (rate_mask & 0xF);
Z
Zhu Yi 已提交
729

730
	D_RATE("Tx sta id: %d, rate: %d (plcp), flags: 0x%4X "
Z
Zhu Yi 已提交
731
		       "cck/ofdm mask: 0x%x/0x%x\n", sta_id,
A
Abhijeet Kolekar 已提交
732 733
		       tx_cmd->rate, le32_to_cpu(tx_cmd->tx_flags),
		       tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
Z
Zhu Yi 已提交
734 735
}

S
Stanislaw Gruszka 已提交
736
static u8 il3945_sync_sta(struct il_priv *il, int sta_id, u16 tx_rate)
Z
Zhu Yi 已提交
737 738
{
	unsigned long flags_spin;
S
Stanislaw Gruszka 已提交
739
	struct il_station_entry *station;
Z
Zhu Yi 已提交
740

S
Stanislaw Gruszka 已提交
741 742
	if (sta_id == IL_INVALID_STATION)
		return IL_INVALID_STATION;
Z
Zhu Yi 已提交
743

S
Stanislaw Gruszka 已提交
744 745
	spin_lock_irqsave(&il->sta_lock, flags_spin);
	station = &il->stations[sta_id];
Z
Zhu Yi 已提交
746 747 748 749

	station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
	station->sta.rate_n_flags = cpu_to_le16(tx_rate);
	station->sta.mode = STA_CONTROL_MODIFY_MSK;
S
Stanislaw Gruszka 已提交
750 751
	il_send_add_sta(il, &station->sta, CMD_ASYNC);
	spin_unlock_irqrestore(&il->sta_lock, flags_spin);
Z
Zhu Yi 已提交
752

753
	D_RATE("SCALE sync station %d to rate %d\n",
Z
Zhu Yi 已提交
754 755 756 757
			sta_id, tx_rate);
	return sta_id;
}

S
Stanislaw Gruszka 已提交
758
static void il3945_set_pwr_vmain(struct il_priv *il)
Z
Zhu Yi 已提交
759
{
760 761 762 763
/*
 * (for documentation purposes)
 * to set power to V_AUX, do

S
Stanislaw Gruszka 已提交
764 765
		if (pci_pme_capable(il->pci_dev, PCI_D3cold)) {
			il_set_bits_mask_prph(il, APMG_PS_CTRL_REG,
Z
Zhu Yi 已提交
766 767 768
					APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
					~APMG_PS_CTRL_MSK_PWR_SRC);

769
			_il_poll_bit(il, CSR_GPIO_IN,
Z
Zhu Yi 已提交
770 771
				     CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
				     CSR_GPIO_IN_BIT_AUX_POWER, 5000);
772
		}
773
 */
Z
Zhu Yi 已提交
774

S
Stanislaw Gruszka 已提交
775
	il_set_bits_mask_prph(il, APMG_PS_CTRL_REG,
776 777
			APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
			~APMG_PS_CTRL_MSK_PWR_SRC);
Z
Zhu Yi 已提交
778

779
	_il_poll_bit(il, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
780
		     CSR_GPIO_IN_BIT_AUX_POWER, 5000);	/* uS */
Z
Zhu Yi 已提交
781 782
}

S
Stanislaw Gruszka 已提交
783
static int il3945_rx_init(struct il_priv *il, struct il_rx_queue *rxq)
Z
Zhu Yi 已提交
784
{
785 786
	il_wr(il, FH39_RCSR_RBD_BASE(0), rxq->bd_dma);
	il_wr(il, FH39_RCSR_RPTR_ADDR(0),
787
					rxq->rb_stts_dma);
788 789
	il_wr(il, FH39_RCSR_WPTR(0), 0);
	il_wr(il, FH39_RCSR_CONFIG(0),
790 791 792 793 794 795 796 797
		FH39_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE |
		FH39_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE |
		FH39_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN |
		FH39_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 |
		(RX_QUEUE_SIZE_LOG << FH39_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE) |
		FH39_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST |
		(1 << FH39_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH) |
		FH39_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH);
Z
Zhu Yi 已提交
798 799

	/* fake read to flush all prev I/O */
800
	il_rd(il, FH39_RSSR_CTRL);
Z
Zhu Yi 已提交
801 802 803 804

	return 0;
}

S
Stanislaw Gruszka 已提交
805
static int il3945_tx_reset(struct il_priv *il)
Z
Zhu Yi 已提交
806 807 808
{

	/* bypass mode */
809
	il_wr_prph(il, ALM_SCD_MODE_REG, 0x2);
Z
Zhu Yi 已提交
810 811

	/* RA 0 is active */
812
	il_wr_prph(il, ALM_SCD_ARASTAT_REG, 0x01);
Z
Zhu Yi 已提交
813 814

	/* all 6 fifo are active */
815
	il_wr_prph(il, ALM_SCD_TXFACT_REG, 0x3f);
Z
Zhu Yi 已提交
816

817 818 819 820
	il_wr_prph(il, ALM_SCD_SBYP_MODE_1_REG, 0x010000);
	il_wr_prph(il, ALM_SCD_SBYP_MODE_2_REG, 0x030002);
	il_wr_prph(il, ALM_SCD_TXF4MF_REG, 0x000004);
	il_wr_prph(il, ALM_SCD_TXF5MF_REG, 0x000005);
Z
Zhu Yi 已提交
821

822
	il_wr(il, FH39_TSSR_CBB_BASE,
S
Stanislaw Gruszka 已提交
823
			     il->_3945.shared_phys);
Z
Zhu Yi 已提交
824

825
	il_wr(il, FH39_TSSR_MSG_CONFIG,
826 827 828 829 830 831 832
		FH39_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON |
		FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON |
		FH39_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B |
		FH39_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON |
		FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON |
		FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH |
		FH39_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH);
Z
Zhu Yi 已提交
833 834 835 836 837 838


	return 0;
}

/**
S
Stanislaw Gruszka 已提交
839
 * il3945_txq_ctx_reset - Reset TX queue context
Z
Zhu Yi 已提交
840 841 842
 *
 * Destroys all DMA structures and initialize them again
 */
S
Stanislaw Gruszka 已提交
843
static int il3945_txq_ctx_reset(struct il_priv *il)
Z
Zhu Yi 已提交
844 845 846 847
{
	int rc;
	int txq_id, slots_num;

S
Stanislaw Gruszka 已提交
848
	il3945_hw_txq_ctx_free(il);
Z
Zhu Yi 已提交
849

850
	/* allocate tx queue structure */
S
Stanislaw Gruszka 已提交
851
	rc = il_alloc_txq_mem(il);
852 853 854
	if (rc)
		return rc;

Z
Zhu Yi 已提交
855
	/* Tx CMD queue */
S
Stanislaw Gruszka 已提交
856
	rc = il3945_tx_reset(il);
Z
Zhu Yi 已提交
857 858 859 860
	if (rc)
		goto error;

	/* Tx queue(s) */
S
Stanislaw Gruszka 已提交
861
	for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
862
		slots_num = (txq_id == IL39_CMD_QUEUE_NUM) ?
Z
Zhu Yi 已提交
863
				TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
S
Stanislaw Gruszka 已提交
864
		rc = il_tx_queue_init(il, &il->txq[txq_id],
865
						slots_num, txq_id);
Z
Zhu Yi 已提交
866
		if (rc) {
867
			IL_ERR("Tx %d queue init failed\n", txq_id);
Z
Zhu Yi 已提交
868 869 870 871 872 873 874
			goto error;
		}
	}

	return rc;

 error:
S
Stanislaw Gruszka 已提交
875
	il3945_hw_txq_ctx_free(il);
Z
Zhu Yi 已提交
876 877 878
	return rc;
}

879

B
Ben Cahill 已提交
880
/*
881
 * Start up 3945's basic functionality after it has been reset
S
Stanislaw Gruszka 已提交
882
 * (e.g. after platform boot, or shutdown via il_apm_stop())
B
Ben Cahill 已提交
883 884
 * NOTE:  This does not load uCode nor start the embedded processor
 */
S
Stanislaw Gruszka 已提交
885
static int il3945_apm_init(struct il_priv *il)
Z
Zhu Yi 已提交
886
{
S
Stanislaw Gruszka 已提交
887
	int ret = il_apm_init(il);
K
Kolekar, Abhijeet 已提交
888

B
Ben Cahill 已提交
889
	/* Clear APMG (NIC's internal power management) interrupts */
890 891
	il_wr_prph(il, APMG_RTC_INT_MSK_REG, 0x0);
	il_wr_prph(il, APMG_RTC_INT_STT_REG, 0xFFFFFFFF);
B
Ben Cahill 已提交
892 893

	/* Reset radio chip */
S
Stanislaw Gruszka 已提交
894
	il_set_bits_prph(il, APMG_PS_CTRL_REG,
895
				APMG_PS_CTRL_VAL_RESET_REQ);
B
Ben Cahill 已提交
896
	udelay(5);
S
Stanislaw Gruszka 已提交
897
	il_clear_bits_prph(il, APMG_PS_CTRL_REG,
898
				APMG_PS_CTRL_VAL_RESET_REQ);
B
Ben Cahill 已提交
899

K
Kolekar, Abhijeet 已提交
900 901
	return ret;
}
Z
Zhu Yi 已提交
902

S
Stanislaw Gruszka 已提交
903
static void il3945_nic_config(struct il_priv *il)
K
Kolekar, Abhijeet 已提交
904
{
S
Stanislaw Gruszka 已提交
905
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
K
Kolekar, Abhijeet 已提交
906
	unsigned long flags;
S
Stanislaw Gruszka 已提交
907
	u8 rev_id = il->pci_dev->revision;
Z
Zhu Yi 已提交
908

S
Stanislaw Gruszka 已提交
909
	spin_lock_irqsave(&il->lock, flags);
Z
Zhu Yi 已提交
910

911
	/* Determine HW type */
912
	D_INFO("HW Revision ID = 0x%X\n", rev_id);
913

Z
Zhu Yi 已提交
914
	if (rev_id & PCI_CFG_REV_ID_BIT_RTP)
915
		D_INFO("RTP type\n");
Z
Zhu Yi 已提交
916
	else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
917
		D_INFO("3945 RADIO-MB type\n");
S
Stanislaw Gruszka 已提交
918
		il_set_bit(il, CSR_HW_IF_CONFIG_REG,
T
Tomas Winkler 已提交
919
			    CSR39_HW_IF_CONFIG_REG_BIT_3945_MB);
Z
Zhu Yi 已提交
920
	} else {
921
		D_INFO("3945 RADIO-MM type\n");
S
Stanislaw Gruszka 已提交
922
		il_set_bit(il, CSR_HW_IF_CONFIG_REG,
T
Tomas Winkler 已提交
923
			    CSR39_HW_IF_CONFIG_REG_BIT_3945_MM);
Z
Zhu Yi 已提交
924 925
	}

926
	if (EEPROM_SKU_CAP_OP_MODE_MRC == eeprom->sku_cap) {
927
		D_INFO("SKU OP mode is mrc\n");
S
Stanislaw Gruszka 已提交
928
		il_set_bit(il, CSR_HW_IF_CONFIG_REG,
T
Tomas Winkler 已提交
929
			    CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC);
Z
Zhu Yi 已提交
930
	} else
931
		D_INFO("SKU OP mode is basic\n");
Z
Zhu Yi 已提交
932

933
	if ((eeprom->board_revision & 0xF0) == 0xD0) {
934
		D_INFO("3945ABG revision is 0x%X\n",
935
			       eeprom->board_revision);
S
Stanislaw Gruszka 已提交
936
		il_set_bit(il, CSR_HW_IF_CONFIG_REG,
T
Tomas Winkler 已提交
937
			    CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
Z
Zhu Yi 已提交
938
	} else {
939
		D_INFO("3945ABG revision is 0x%X\n",
940
			       eeprom->board_revision);
S
Stanislaw Gruszka 已提交
941
		il_clear_bit(il, CSR_HW_IF_CONFIG_REG,
T
Tomas Winkler 已提交
942
			      CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
Z
Zhu Yi 已提交
943 944
	}

945
	if (eeprom->almgor_m_version <= 1) {
S
Stanislaw Gruszka 已提交
946
		il_set_bit(il, CSR_HW_IF_CONFIG_REG,
T
Tomas Winkler 已提交
947
			    CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
948
		D_INFO("Card M type A version is 0x%X\n",
949
			       eeprom->almgor_m_version);
Z
Zhu Yi 已提交
950
	} else {
951
		D_INFO("Card M type B version is 0x%X\n",
952
			       eeprom->almgor_m_version);
S
Stanislaw Gruszka 已提交
953
		il_set_bit(il, CSR_HW_IF_CONFIG_REG,
T
Tomas Winkler 已提交
954
			    CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
Z
Zhu Yi 已提交
955
	}
S
Stanislaw Gruszka 已提交
956
	spin_unlock_irqrestore(&il->lock, flags);
Z
Zhu Yi 已提交
957

958
	if (eeprom->sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
959
		D_RF_KILL("SW RF KILL supported in EEPROM.\n");
Z
Zhu Yi 已提交
960

961
	if (eeprom->sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
962
		D_RF_KILL("HW RF KILL supported in EEPROM.\n");
K
Kolekar, Abhijeet 已提交
963 964
}

S
Stanislaw Gruszka 已提交
965
int il3945_hw_nic_init(struct il_priv *il)
K
Kolekar, Abhijeet 已提交
966 967 968
{
	int rc;
	unsigned long flags;
S
Stanislaw Gruszka 已提交
969
	struct il_rx_queue *rxq = &il->rxq;
K
Kolekar, Abhijeet 已提交
970

S
Stanislaw Gruszka 已提交
971 972 973
	spin_lock_irqsave(&il->lock, flags);
	il->cfg->ops->lib->apm_ops.init(il);
	spin_unlock_irqrestore(&il->lock, flags);
K
Kolekar, Abhijeet 已提交
974

S
Stanislaw Gruszka 已提交
975
	il3945_set_pwr_vmain(il);
K
Kolekar, Abhijeet 已提交
976

S
Stanislaw Gruszka 已提交
977
	il->cfg->ops->lib->apm_ops.config(il);
Z
Zhu Yi 已提交
978 979 980

	/* Allocate the RX queue, or reset if it is already allocated */
	if (!rxq->bd) {
S
Stanislaw Gruszka 已提交
981
		rc = il_rx_queue_alloc(il);
Z
Zhu Yi 已提交
982
		if (rc) {
983
			IL_ERR("Unable to initialize Rx queue\n");
Z
Zhu Yi 已提交
984 985 986
			return -ENOMEM;
		}
	} else
S
Stanislaw Gruszka 已提交
987
		il3945_rx_queue_reset(il, rxq);
Z
Zhu Yi 已提交
988

S
Stanislaw Gruszka 已提交
989
	il3945_rx_replenish(il);
Z
Zhu Yi 已提交
990

S
Stanislaw Gruszka 已提交
991
	il3945_rx_init(il, rxq);
Z
Zhu Yi 已提交
992 993 994 995


	/* Look at using this instead:
	rxq->need_update = 1;
S
Stanislaw Gruszka 已提交
996
	il_rx_queue_update_write_ptr(il, rxq);
Z
Zhu Yi 已提交
997 998
	*/

999
	il_wr(il, FH39_RCSR_WPTR(0), rxq->write & ~7);
Z
Zhu Yi 已提交
1000

S
Stanislaw Gruszka 已提交
1001
	rc = il3945_txq_ctx_reset(il);
Z
Zhu Yi 已提交
1002 1003 1004
	if (rc)
		return rc;

S
Stanislaw Gruszka 已提交
1005
	set_bit(S_INIT, &il->status);
Z
Zhu Yi 已提交
1006 1007 1008 1009 1010

	return 0;
}

/**
S
Stanislaw Gruszka 已提交
1011
 * il3945_hw_txq_ctx_free - Free TXQ Context
Z
Zhu Yi 已提交
1012 1013 1014
 *
 * Destroy all TX DMA queues and structures
 */
S
Stanislaw Gruszka 已提交
1015
void il3945_hw_txq_ctx_free(struct il_priv *il)
Z
Zhu Yi 已提交
1016 1017 1018 1019
{
	int txq_id;

	/* Tx queues */
S
Stanislaw Gruszka 已提交
1020 1021
	if (il->txq)
		for (txq_id = 0; txq_id < il->hw_params.max_txq_num;
1022
		     txq_id++)
1023
			if (txq_id == IL39_CMD_QUEUE_NUM)
S
Stanislaw Gruszka 已提交
1024
				il_cmd_queue_free(il);
1025
			else
S
Stanislaw Gruszka 已提交
1026
				il_tx_queue_free(il, txq_id);
1027

1028
	/* free tx queue structure */
S
Stanislaw Gruszka 已提交
1029
	il_txq_mem(il);
Z
Zhu Yi 已提交
1030 1031
}

S
Stanislaw Gruszka 已提交
1032
void il3945_hw_txq_ctx_stop(struct il_priv *il)
Z
Zhu Yi 已提交
1033
{
1034
	int txq_id;
Z
Zhu Yi 已提交
1035 1036

	/* stop SCD */
1037 1038
	il_wr_prph(il, ALM_SCD_MODE_REG, 0);
	il_wr_prph(il, ALM_SCD_TXFACT_REG, 0);
Z
Zhu Yi 已提交
1039 1040

	/* reset TFD queues */
S
Stanislaw Gruszka 已提交
1041
	for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
1042 1043
		il_wr(il, FH39_TCSR_CONFIG(txq_id), 0x0);
		il_poll_bit(il, FH39_TSSR_TX_STATUS,
1044
				FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
Z
Zhu Yi 已提交
1045 1046 1047
				1000);
	}

S
Stanislaw Gruszka 已提交
1048
	il3945_hw_txq_ctx_free(il);
Z
Zhu Yi 已提交
1049 1050 1051
}

/**
S
Stanislaw Gruszka 已提交
1052
 * il3945_hw_reg_adjust_power_by_temp
S
Stanislaw Gruszka 已提交
1053
 * return idx delta into power gain settings table
1054
*/
S
Stanislaw Gruszka 已提交
1055
static int il3945_hw_reg_adjust_power_by_temp(int new_reading, int old_reading)
Z
Zhu Yi 已提交
1056 1057 1058 1059 1060
{
	return (new_reading - old_reading) * (-11) / 100;
}

/**
S
Stanislaw Gruszka 已提交
1061
 * il3945_hw_reg_temp_out_of_range - Keep temperature in sane range
Z
Zhu Yi 已提交
1062
 */
S
Stanislaw Gruszka 已提交
1063
static inline int il3945_hw_reg_temp_out_of_range(int temperature)
Z
Zhu Yi 已提交
1064
{
1065
	return (temperature < -260 || temperature > 25) ? 1 : 0;
Z
Zhu Yi 已提交
1066 1067
}

S
Stanislaw Gruszka 已提交
1068
int il3945_hw_get_temperature(struct il_priv *il)
Z
Zhu Yi 已提交
1069
{
1070
	return _il_rd(il, CSR_UCODE_DRV_GP2);
Z
Zhu Yi 已提交
1071 1072 1073
}

/**
S
Stanislaw Gruszka 已提交
1074
 * il3945_hw_reg_txpower_get_temperature
1075 1076
 * get the current temperature by reading from NIC
*/
S
Stanislaw Gruszka 已提交
1077
static int il3945_hw_reg_txpower_get_temperature(struct il_priv *il)
Z
Zhu Yi 已提交
1078
{
S
Stanislaw Gruszka 已提交
1079
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
Z
Zhu Yi 已提交
1080 1081
	int temperature;

S
Stanislaw Gruszka 已提交
1082
	temperature = il3945_hw_get_temperature(il);
Z
Zhu Yi 已提交
1083 1084 1085

	/* driver's okay range is -260 to +25.
	 *   human readable okay range is 0 to +285 */
1086
	D_INFO("Temperature: %d\n", temperature + IL_TEMP_CONVERT);
Z
Zhu Yi 已提交
1087 1088

	/* handle insane temp reading */
S
Stanislaw Gruszka 已提交
1089
	if (il3945_hw_reg_temp_out_of_range(temperature)) {
1090
		IL_ERR("Error bad temperature value  %d\n", temperature);
Z
Zhu Yi 已提交
1091 1092 1093

		/* if really really hot(?),
		 *   substitute the 3rd band/group's temp measured at factory */
S
Stanislaw Gruszka 已提交
1094
		if (il->last_temperature > 100)
1095
			temperature = eeprom->groups[2].temperature;
Z
Zhu Yi 已提交
1096
		else /* else use most recent "sane" value from driver */
S
Stanislaw Gruszka 已提交
1097
			temperature = il->last_temperature;
Z
Zhu Yi 已提交
1098 1099 1100 1101 1102 1103 1104 1105
	}

	return temperature;	/* raw, not "human readable" */
}

/* Adjust Txpower only if temperature variance is greater than threshold.
 *
 * Both are lower than older versions' 9 degrees */
S
Stanislaw Gruszka 已提交
1106
#define IL_TEMPERATURE_LIMIT_TIMER   6
Z
Zhu Yi 已提交
1107 1108

/**
S
Stanislaw Gruszka 已提交
1109
 * il3945_is_temp_calib_needed - determines if new calibration is needed
Z
Zhu Yi 已提交
1110 1111 1112 1113
 *
 * records new temperature in tx_mgr->temperature.
 * replaces tx_mgr->last_temperature *only* if calib needed
 *    (assumes caller will actually do the calibration!). */
S
Stanislaw Gruszka 已提交
1114
static int il3945_is_temp_calib_needed(struct il_priv *il)
Z
Zhu Yi 已提交
1115 1116 1117
{
	int temp_diff;

S
Stanislaw Gruszka 已提交
1118 1119
	il->temperature = il3945_hw_reg_txpower_get_temperature(il);
	temp_diff = il->temperature - il->last_temperature;
Z
Zhu Yi 已提交
1120 1121 1122

	/* get absolute value */
	if (temp_diff < 0) {
1123
		D_POWER("Getting cooler, delta %d,\n", temp_diff);
Z
Zhu Yi 已提交
1124 1125
		temp_diff = -temp_diff;
	} else if (temp_diff == 0)
1126
		D_POWER("Same temp,\n");
Z
Zhu Yi 已提交
1127
	else
1128
		D_POWER("Getting warmer, delta %d,\n", temp_diff);
Z
Zhu Yi 已提交
1129 1130

	/* if we don't need calibration, *don't* update last_temperature */
S
Stanislaw Gruszka 已提交
1131
	if (temp_diff < IL_TEMPERATURE_LIMIT_TIMER) {
1132
		D_POWER("Timed thermal calib not needed\n");
Z
Zhu Yi 已提交
1133 1134 1135
		return 0;
	}

1136
	D_POWER("Timed thermal calib needed\n");
Z
Zhu Yi 已提交
1137 1138 1139

	/* assume that caller will actually do calib ...
	 *   update the "last temperature" value */
S
Stanislaw Gruszka 已提交
1140
	il->last_temperature = il->temperature;
Z
Zhu Yi 已提交
1141 1142 1143
	return 1;
}

S
Stanislaw Gruszka 已提交
1144 1145
#define IL_MAX_GAIN_ENTRIES 78
#define IL_CCK_FROM_OFDM_POWER_DIFF  -5
S
Stanislaw Gruszka 已提交
1146
#define IL_CCK_FROM_OFDM_IDX_DIFF (10)
Z
Zhu Yi 已提交
1147 1148 1149

/* radio and DSP power table, each step is 1/2 dB.
 * 1st number is for RF analog gain, 2nd number is for DSP pre-DAC gain. */
S
Stanislaw Gruszka 已提交
1150
static struct il3945_tx_power power_gain_table[2][IL_MAX_GAIN_ENTRIES] = {
Z
Zhu Yi 已提交
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
	{
	 {251, 127},		/* 2.4 GHz, highest power */
	 {251, 127},
	 {251, 127},
	 {251, 127},
	 {251, 125},
	 {251, 110},
	 {251, 105},
	 {251, 98},
	 {187, 125},
	 {187, 115},
	 {187, 108},
	 {187, 99},
	 {243, 119},
	 {243, 111},
	 {243, 105},
	 {243, 97},
	 {243, 92},
	 {211, 106},
	 {211, 100},
	 {179, 120},
	 {179, 113},
	 {179, 107},
	 {147, 125},
	 {147, 119},
	 {147, 112},
	 {147, 106},
	 {147, 101},
	 {147, 97},
	 {147, 91},
	 {115, 107},
	 {235, 121},
	 {235, 115},
	 {235, 109},
	 {203, 127},
	 {203, 121},
	 {203, 115},
	 {203, 108},
	 {203, 102},
	 {203, 96},
	 {203, 92},
	 {171, 110},
	 {171, 104},
	 {171, 98},
	 {139, 116},
	 {227, 125},
	 {227, 119},
	 {227, 113},
	 {227, 107},
	 {227, 101},
	 {227, 96},
	 {195, 113},
	 {195, 106},
	 {195, 102},
	 {195, 95},
	 {163, 113},
	 {163, 106},
	 {163, 102},
	 {163, 95},
	 {131, 113},
	 {131, 106},
	 {131, 102},
	 {131, 95},
	 {99, 113},
	 {99, 106},
	 {99, 102},
	 {99, 95},
	 {67, 113},
	 {67, 106},
	 {67, 102},
	 {67, 95},
	 {35, 113},
	 {35, 106},
	 {35, 102},
	 {35, 95},
	 {3, 113},
	 {3, 106},
	 {3, 102},
	 {3, 95} },		/* 2.4 GHz, lowest power */
	{
	 {251, 127},		/* 5.x GHz, highest power */
	 {251, 120},
	 {251, 114},
	 {219, 119},
	 {219, 101},
	 {187, 113},
	 {187, 102},
	 {155, 114},
	 {155, 103},
	 {123, 117},
	 {123, 107},
	 {123, 99},
	 {123, 92},
	 {91, 108},
	 {59, 125},
	 {59, 118},
	 {59, 109},
	 {59, 102},
	 {59, 96},
	 {59, 90},
	 {27, 104},
	 {27, 98},
	 {27, 92},
	 {115, 118},
	 {115, 111},
	 {115, 104},
	 {83, 126},
	 {83, 121},
	 {83, 113},
	 {83, 105},
	 {83, 99},
	 {51, 118},
	 {51, 111},
	 {51, 104},
	 {51, 98},
	 {19, 116},
	 {19, 109},
	 {19, 102},
	 {19, 98},
	 {19, 93},
	 {171, 113},
	 {171, 107},
	 {171, 99},
	 {139, 120},
	 {139, 113},
	 {139, 107},
	 {139, 99},
	 {107, 120},
	 {107, 113},
	 {107, 107},
	 {107, 99},
	 {75, 120},
	 {75, 113},
	 {75, 107},
	 {75, 99},
	 {43, 120},
	 {43, 113},
	 {43, 107},
	 {43, 99},
	 {11, 120},
	 {11, 113},
	 {11, 107},
	 {11, 99},
	 {131, 107},
	 {131, 99},
	 {99, 120},
	 {99, 113},
	 {99, 107},
	 {99, 99},
	 {67, 120},
	 {67, 113},
	 {67, 107},
	 {67, 99},
	 {35, 120},
	 {35, 113},
	 {35, 107},
	 {35, 99},
	 {3, 120} }		/* 5.x GHz, lowest power */
};

S
Stanislaw Gruszka 已提交
1311
static inline u8 il3945_hw_reg_fix_power_idx(int idx)
Z
Zhu Yi 已提交
1312
{
S
Stanislaw Gruszka 已提交
1313
	if (idx < 0)
Z
Zhu Yi 已提交
1314
		return 0;
S
Stanislaw Gruszka 已提交
1315
	if (idx >= IL_MAX_GAIN_ENTRIES)
S
Stanislaw Gruszka 已提交
1316
		return IL_MAX_GAIN_ENTRIES - 1;
S
Stanislaw Gruszka 已提交
1317
	return (u8) idx;
Z
Zhu Yi 已提交
1318 1319 1320 1321 1322 1323
}

/* Kick off thermal recalibration check every 60 seconds */
#define REG_RECALIB_PERIOD (60)

/**
S
Stanislaw Gruszka 已提交
1324
 * il3945_hw_reg_set_scan_power - Set Tx power for scan probe requests
Z
Zhu Yi 已提交
1325 1326 1327 1328
 *
 * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK)
 * or 6 Mbit (OFDM) rates.
 */
S
Stanislaw Gruszka 已提交
1329 1330
static void il3945_hw_reg_set_scan_power(struct il_priv *il, u32 scan_tbl_idx,
			       s32 rate_idx, const s8 *clip_pwrs,
S
Stanislaw Gruszka 已提交
1331
			       struct il_channel_info *ch_info,
S
Stanislaw Gruszka 已提交
1332
			       int band_idx)
Z
Zhu Yi 已提交
1333
{
S
Stanislaw Gruszka 已提交
1334
	struct il3945_scan_power_info *scan_power_info;
Z
Zhu Yi 已提交
1335
	s8 power;
S
Stanislaw Gruszka 已提交
1336
	u8 power_idx;
Z
Zhu Yi 已提交
1337

S
Stanislaw Gruszka 已提交
1338
	scan_power_info = &ch_info->scan_pwr_info[scan_tbl_idx];
Z
Zhu Yi 已提交
1339 1340 1341 1342

	/* use this channel group's 6Mbit clipping/saturation pwr,
	 *   but cap at regulatory scan power restriction (set during init
	 *   based on eeprom channel data) for this channel.  */
S
Stanislaw Gruszka 已提交
1343
	power = min(ch_info->scan_power, clip_pwrs[RATE_6M_IDX_TBL]);
Z
Zhu Yi 已提交
1344

S
Stanislaw Gruszka 已提交
1345
	power = min(power, il->tx_power_user_lmt);
Z
Zhu Yi 已提交
1346 1347 1348 1349
	scan_power_info->requested_power = power;

	/* find difference between new scan *power* and current "normal"
	 *   Tx *power* for 6Mb.  Use this difference (x2) to adjust the
S
Stanislaw Gruszka 已提交
1350
	 *   current "normal" temperature-compensated Tx power *idx* for
Z
Zhu Yi 已提交
1351
	 *   this rate (1Mb or 6Mb) to yield new temp-compensated scan power
S
Stanislaw Gruszka 已提交
1352 1353
	 *   *idx*. */
	power_idx = ch_info->power_info[rate_idx].power_table_idx
Z
Zhu Yi 已提交
1354
	    - (power - ch_info->power_info
S
Stanislaw Gruszka 已提交
1355
	       [RATE_6M_IDX_TBL].requested_power) * 2;
Z
Zhu Yi 已提交
1356

S
Stanislaw Gruszka 已提交
1357
	/* store reference idx that we use when adjusting *all* scan
Z
Zhu Yi 已提交
1358 1359 1360
	 *   powers.  So we can accommodate user (all channel) or spectrum
	 *   management (single channel) power changes "between" temperature
	 *   feedback compensation procedures.
S
Stanislaw Gruszka 已提交
1361
	 * don't force fit this reference idx into gain table; it may be a
Z
Zhu Yi 已提交
1362 1363 1364 1365 1366
	 *   negative number.  This will help avoid errors when we're at
	 *   the lower bounds (highest gains, for warmest temperatures)
	 *   of the table. */

	/* don't exceed table bounds for "real" setting */
S
Stanislaw Gruszka 已提交
1367
	power_idx = il3945_hw_reg_fix_power_idx(power_idx);
Z
Zhu Yi 已提交
1368

S
Stanislaw Gruszka 已提交
1369
	scan_power_info->power_table_idx = power_idx;
Z
Zhu Yi 已提交
1370
	scan_power_info->tpc.tx_gain =
S
Stanislaw Gruszka 已提交
1371
	    power_gain_table[band_idx][power_idx].tx_gain;
Z
Zhu Yi 已提交
1372
	scan_power_info->tpc.dsp_atten =
S
Stanislaw Gruszka 已提交
1373
	    power_gain_table[band_idx][power_idx].dsp_atten;
Z
Zhu Yi 已提交
1374 1375 1376
}

/**
S
Stanislaw Gruszka 已提交
1377
 * il3945_send_tx_power - fill in Tx Power command with gain settings
Z
Zhu Yi 已提交
1378 1379 1380 1381
 *
 * Configures power settings for all rates for the current channel,
 * using values from channel info struct, and send to NIC
 */
S
Stanislaw Gruszka 已提交
1382
static int il3945_send_tx_power(struct il_priv *il)
Z
Zhu Yi 已提交
1383
{
1384
	int rate_idx, i;
S
Stanislaw Gruszka 已提交
1385 1386
	const struct il_channel_info *ch_info = NULL;
	struct il3945_txpowertable_cmd txpower = {
1387
		.channel = il->ctx.active.channel,
Z
Zhu Yi 已提交
1388
	};
1389 1390
	u16 chan;

S
Stanislaw Gruszka 已提交
1391
	if (WARN_ONCE(test_bit(S_SCAN_HW, &il->status),
1392 1393 1394
		      "TX Power requested while scanning!\n"))
		return -EAGAIN;

1395
	chan = le16_to_cpu(il->ctx.active.channel);
Z
Zhu Yi 已提交
1396

S
Stanislaw Gruszka 已提交
1397 1398
	txpower.band = (il->band == IEEE80211_BAND_5GHZ) ? 0 : 1;
	ch_info = il_get_channel_info(il, il->band, chan);
Z
Zhu Yi 已提交
1399
	if (!ch_info) {
1400
		IL_ERR(
1401
			"Failed to get channel info for channel %d [%d]\n",
S
Stanislaw Gruszka 已提交
1402
			chan, il->band);
Z
Zhu Yi 已提交
1403 1404 1405
		return -EINVAL;
	}

S
Stanislaw Gruszka 已提交
1406
	if (!il_is_channel_valid(ch_info)) {
S
Stanislaw Gruszka 已提交
1407
		D_POWER("Not calling TX_PWR_TBL_CMD on "
Z
Zhu Yi 已提交
1408 1409 1410 1411 1412
				"non-Tx channel.\n");
		return 0;
	}

	/* fill cmd with power settings for all rates for current channel */
1413
	/* Fill OFDM rate */
S
Stanislaw Gruszka 已提交
1414
	for (rate_idx = IL_FIRST_OFDM_RATE, i = 0;
1415
	     rate_idx <= IL39_LAST_OFDM_RATE; rate_idx++, i++) {
1416 1417

		txpower.power[i].tpc = ch_info->power_info[i].tpc;
S
Stanislaw Gruszka 已提交
1418
		txpower.power[i].rate = il3945_rates[rate_idx].plcp;
Z
Zhu Yi 已提交
1419

1420
		D_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n",
Z
Zhu Yi 已提交
1421 1422
				le16_to_cpu(txpower.channel),
				txpower.band,
1423 1424 1425 1426 1427
				txpower.power[i].tpc.tx_gain,
				txpower.power[i].tpc.dsp_atten,
				txpower.power[i].rate);
	}
	/* Fill CCK rates */
S
Stanislaw Gruszka 已提交
1428 1429
	for (rate_idx = IL_FIRST_CCK_RATE;
	     rate_idx <= IL_LAST_CCK_RATE; rate_idx++, i++) {
1430
		txpower.power[i].tpc = ch_info->power_info[i].tpc;
S
Stanislaw Gruszka 已提交
1431
		txpower.power[i].rate = il3945_rates[rate_idx].plcp;
1432

1433
		D_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n",
1434 1435 1436 1437 1438
				le16_to_cpu(txpower.channel),
				txpower.band,
				txpower.power[i].tpc.tx_gain,
				txpower.power[i].tpc.dsp_atten,
				txpower.power[i].rate);
Z
Zhu Yi 已提交
1439 1440
	}

1441
	return il_send_cmd_pdu(il, C_TX_PWR_TBL,
S
Stanislaw Gruszka 已提交
1442
				sizeof(struct il3945_txpowertable_cmd),
1443
				&txpower);
Z
Zhu Yi 已提交
1444 1445 1446 1447

}

/**
S
Stanislaw Gruszka 已提交
1448
 * il3945_hw_reg_set_new_power - Configures power tables at new levels
Z
Zhu Yi 已提交
1449 1450
 * @ch_info: Channel to update.  Uses power_info.requested_power.
 *
S
Stanislaw Gruszka 已提交
1451
 * Replace requested_power and base_power_idx ch_info fields for
Z
Zhu Yi 已提交
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462
 * one channel.
 *
 * Called if user or spectrum management changes power preferences.
 * Takes into account h/w and modulation limitations (clip power).
 *
 * This does *not* send anything to NIC, just sets up ch_info for one channel.
 *
 * NOTE: reg_compensate_for_temperature_dif() *must* be run after this to
 *	 properly fill out the scan powers, and actual h/w gain settings,
 *	 and send changes to NIC
 */
S
Stanislaw Gruszka 已提交
1463
static int il3945_hw_reg_set_new_power(struct il_priv *il,
S
Stanislaw Gruszka 已提交
1464
			     struct il_channel_info *ch_info)
Z
Zhu Yi 已提交
1465
{
S
Stanislaw Gruszka 已提交
1466
	struct il3945_channel_power_info *power_info;
Z
Zhu Yi 已提交
1467 1468 1469 1470 1471 1472
	int power_changed = 0;
	int i;
	const s8 *clip_pwrs;
	int power;

	/* Get this chnlgrp's rate-to-max/clip-powers table */
S
Stanislaw Gruszka 已提交
1473
	clip_pwrs = il->_3945.clip_groups[ch_info->group_idx].clip_powers;
Z
Zhu Yi 已提交
1474 1475 1476 1477 1478

	/* Get this channel's rate-to-current-power settings table */
	power_info = ch_info->power_info;

	/* update OFDM Txpower settings */
S
Stanislaw Gruszka 已提交
1479
	for (i = RATE_6M_IDX_TBL; i <= RATE_54M_IDX_TBL;
Z
Zhu Yi 已提交
1480 1481 1482 1483 1484 1485 1486 1487 1488
	     i++, ++power_info) {
		int delta_idx;

		/* limit new power to be no more than h/w capability */
		power = min(ch_info->curr_txpow, clip_pwrs[i]);
		if (power == power_info->requested_power)
			continue;

		/* find difference between old and new requested powers,
S
Stanislaw Gruszka 已提交
1489
		 *    update base (non-temp-compensated) power idx */
Z
Zhu Yi 已提交
1490
		delta_idx = (power - power_info->requested_power) * 2;
S
Stanislaw Gruszka 已提交
1491
		power_info->base_power_idx -= delta_idx;
Z
Zhu Yi 已提交
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502

		/* save new requested power value */
		power_info->requested_power = power;

		power_changed = 1;
	}

	/* update CCK Txpower settings, based on OFDM 12M setting ...
	 *    ... all CCK power settings for a given channel are the *same*. */
	if (power_changed) {
		power =
S
Stanislaw Gruszka 已提交
1503
		    ch_info->power_info[RATE_12M_IDX_TBL].
S
Stanislaw Gruszka 已提交
1504
		    requested_power + IL_CCK_FROM_OFDM_POWER_DIFF;
Z
Zhu Yi 已提交
1505

S
Stanislaw Gruszka 已提交
1506
		/* do all CCK rates' il3945_channel_power_info structures */
S
Stanislaw Gruszka 已提交
1507
		for (i = RATE_1M_IDX_TBL; i <= RATE_11M_IDX_TBL; i++) {
Z
Zhu Yi 已提交
1508
			power_info->requested_power = power;
S
Stanislaw Gruszka 已提交
1509
			power_info->base_power_idx =
S
Stanislaw Gruszka 已提交
1510
			    ch_info->power_info[RATE_12M_IDX_TBL].
S
Stanislaw Gruszka 已提交
1511
			    base_power_idx + IL_CCK_FROM_OFDM_IDX_DIFF;
Z
Zhu Yi 已提交
1512 1513 1514 1515 1516 1517 1518 1519
			++power_info;
		}
	}

	return 0;
}

/**
S
Stanislaw Gruszka 已提交
1520
 * il3945_hw_reg_get_ch_txpower_limit - returns new power limit for channel
Z
Zhu Yi 已提交
1521 1522 1523 1524 1525
 *
 * NOTE: Returned power limit may be less (but not more) than requested,
 *	 based strictly on regulatory (eeprom and spectrum mgt) limitations
 *	 (no consideration for h/w clipping limitations).
 */
S
Stanislaw Gruszka 已提交
1526
static int il3945_hw_reg_get_ch_txpower_limit(struct il_channel_info *ch_info)
Z
Zhu Yi 已提交
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
{
	s8 max_power;

#if 0
	/* if we're using TGd limits, use lower of TGd or EEPROM */
	if (ch_info->tgd_data.max_power != 0)
		max_power = min(ch_info->tgd_data.max_power,
				ch_info->eeprom.max_power_avg);

	/* else just use EEPROM limits */
	else
#endif
		max_power = ch_info->eeprom.max_power_avg;

	return min(max_power, ch_info->max_power_avg);
}

/**
S
Stanislaw Gruszka 已提交
1545
 * il3945_hw_reg_comp_txpower_temp - Compensate for temperature
Z
Zhu Yi 已提交
1546 1547 1548 1549
 *
 * Compensate txpower settings of *all* channels for temperature.
 * This only accounts for the difference between current temperature
 *   and the factory calibration temperatures, and bases the new settings
S
Stanislaw Gruszka 已提交
1550
 *   on the channel's base_power_idx.
Z
Zhu Yi 已提交
1551 1552 1553
 *
 * If RxOn is "associated", this sends the new Txpower to NIC!
 */
S
Stanislaw Gruszka 已提交
1554
static int il3945_hw_reg_comp_txpower_temp(struct il_priv *il)
Z
Zhu Yi 已提交
1555
{
S
Stanislaw Gruszka 已提交
1556
	struct il_channel_info *ch_info = NULL;
S
Stanislaw Gruszka 已提交
1557
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
S
Stanislaw Gruszka 已提交
1558
	int delta_idx;
Z
Zhu Yi 已提交
1559 1560
	const s8 *clip_pwrs; /* array of h/w max power levels for each rate */
	u8 a_band;
S
Stanislaw Gruszka 已提交
1561 1562
	u8 rate_idx;
	u8 scan_tbl_idx;
Z
Zhu Yi 已提交
1563 1564
	u8 i;
	int ref_temp;
S
Stanislaw Gruszka 已提交
1565
	int temperature = il->temperature;
Z
Zhu Yi 已提交
1566

S
Stanislaw Gruszka 已提交
1567
	if (il->disable_tx_power_cal ||
S
Stanislaw Gruszka 已提交
1568
	    test_bit(S_SCANNING, &il->status)) {
1569 1570 1571
		/* do not perform tx power calibration */
		return 0;
	}
Z
Zhu Yi 已提交
1572
	/* set up new Tx power info for each and every channel, 2.4 and 5.x */
S
Stanislaw Gruszka 已提交
1573 1574
	for (i = 0; i < il->channel_count; i++) {
		ch_info = &il->channel_info[i];
S
Stanislaw Gruszka 已提交
1575
		a_band = il_is_channel_a_band(ch_info);
Z
Zhu Yi 已提交
1576 1577

		/* Get this chnlgrp's factory calibration temperature */
S
Stanislaw Gruszka 已提交
1578
		ref_temp = (s16)eeprom->groups[ch_info->group_idx].
Z
Zhu Yi 已提交
1579 1580
		    temperature;

S
Stanislaw Gruszka 已提交
1581
		/* get power idx adjustment based on current and factory
Z
Zhu Yi 已提交
1582
		 * temps */
S
Stanislaw Gruszka 已提交
1583
		delta_idx = il3945_hw_reg_adjust_power_by_temp(temperature,
Z
Zhu Yi 已提交
1584 1585 1586
							      ref_temp);

		/* set tx power value for all rates, OFDM and CCK */
S
Stanislaw Gruszka 已提交
1587 1588
		for (rate_idx = 0; rate_idx < RATE_COUNT_3945;
		     rate_idx++) {
Z
Zhu Yi 已提交
1589
			int power_idx =
S
Stanislaw Gruszka 已提交
1590
			    ch_info->power_info[rate_idx].base_power_idx;
Z
Zhu Yi 已提交
1591 1592

			/* temperature compensate */
S
Stanislaw Gruszka 已提交
1593
			power_idx += delta_idx;
Z
Zhu Yi 已提交
1594 1595

			/* stay within table range */
S
Stanislaw Gruszka 已提交
1596 1597 1598 1599
			power_idx = il3945_hw_reg_fix_power_idx(power_idx);
			ch_info->power_info[rate_idx].
			    power_table_idx = (u8) power_idx;
			ch_info->power_info[rate_idx].tpc =
Z
Zhu Yi 已提交
1600 1601 1602 1603
			    power_gain_table[a_band][power_idx];
		}

		/* Get this chnlgrp's rate-to-max/clip-powers table */
S
Stanislaw Gruszka 已提交
1604
		clip_pwrs = il->_3945.clip_groups[ch_info->group_idx].clip_powers;
Z
Zhu Yi 已提交
1605 1606

		/* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */
S
Stanislaw Gruszka 已提交
1607 1608 1609
		for (scan_tbl_idx = 0;
		     scan_tbl_idx < IL_NUM_SCAN_RATES; scan_tbl_idx++) {
			s32 actual_idx = (scan_tbl_idx == 0) ?
S
Stanislaw Gruszka 已提交
1610
			    RATE_1M_IDX_TBL : RATE_6M_IDX_TBL;
S
Stanislaw Gruszka 已提交
1611 1612
			il3945_hw_reg_set_scan_power(il, scan_tbl_idx,
					   actual_idx, clip_pwrs,
Z
Zhu Yi 已提交
1613 1614 1615 1616 1617
					   ch_info, a_band);
		}
	}

	/* send Txpower command for current channel to ucode */
S
Stanislaw Gruszka 已提交
1618
	return il->cfg->ops->lib->send_tx_power(il);
Z
Zhu Yi 已提交
1619 1620
}

S
Stanislaw Gruszka 已提交
1621
int il3945_hw_reg_set_txpower(struct il_priv *il, s8 power)
Z
Zhu Yi 已提交
1622
{
S
Stanislaw Gruszka 已提交
1623
	struct il_channel_info *ch_info;
Z
Zhu Yi 已提交
1624 1625 1626 1627
	s8 max_power;
	u8 a_band;
	u8 i;

S
Stanislaw Gruszka 已提交
1628
	if (il->tx_power_user_lmt == power) {
1629
		D_POWER("Requested Tx power same as current "
Z
Zhu Yi 已提交
1630 1631 1632 1633
				"limit: %ddBm.\n", power);
		return 0;
	}

1634
	D_POWER("Setting upper limit clamp to %ddBm.\n", power);
S
Stanislaw Gruszka 已提交
1635
	il->tx_power_user_lmt = power;
Z
Zhu Yi 已提交
1636 1637 1638

	/* set up new Tx powers for each and every channel, 2.4 and 5.x */

S
Stanislaw Gruszka 已提交
1639 1640
	for (i = 0; i < il->channel_count; i++) {
		ch_info = &il->channel_info[i];
S
Stanislaw Gruszka 已提交
1641
		a_band = il_is_channel_a_band(ch_info);
Z
Zhu Yi 已提交
1642 1643 1644

		/* find minimum power of all user and regulatory constraints
		 *    (does not consider h/w clipping limitations) */
S
Stanislaw Gruszka 已提交
1645
		max_power = il3945_hw_reg_get_ch_txpower_limit(ch_info);
Z
Zhu Yi 已提交
1646 1647 1648 1649 1650
		max_power = min(power, max_power);
		if (max_power != ch_info->curr_txpow) {
			ch_info->curr_txpow = max_power;

			/* this considers the h/w clipping limitations */
S
Stanislaw Gruszka 已提交
1651
			il3945_hw_reg_set_new_power(il, ch_info);
Z
Zhu Yi 已提交
1652 1653 1654 1655 1656
		}
	}

	/* update txpower settings for all channels,
	 *   send to NIC if associated. */
S
Stanislaw Gruszka 已提交
1657 1658
	il3945_is_temp_calib_needed(il);
	il3945_hw_reg_comp_txpower_temp(il);
Z
Zhu Yi 已提交
1659 1660 1661 1662

	return 0;
}

S
Stanislaw Gruszka 已提交
1663
static int il3945_send_rxon_assoc(struct il_priv *il,
S
Stanislaw Gruszka 已提交
1664
				   struct il_rxon_context *ctx)
1665 1666
{
	int rc = 0;
1667
	struct il_rx_pkt *pkt;
S
Stanislaw Gruszka 已提交
1668 1669
	struct il3945_rxon_assoc_cmd rxon_assoc;
	struct il_host_cmd cmd = {
1670
		.id = C_RXON_ASSOC,
1671
		.len = sizeof(rxon_assoc),
J
Johannes Berg 已提交
1672
		.flags = CMD_WANT_SKB,
1673 1674
		.data = &rxon_assoc,
	};
S
Stanislaw Gruszka 已提交
1675 1676
	const struct il_rxon_cmd *rxon1 = &ctx->staging;
	const struct il_rxon_cmd *rxon2 = &ctx->active;
1677

1678 1679 1680 1681
	if (rxon1->flags == rxon2->flags &&
	    rxon1->filter_flags == rxon2->filter_flags &&
	    rxon1->cck_basic_rates == rxon2->cck_basic_rates &&
	    rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates) {
1682
		D_INFO("Using current RXON_ASSOC.  Not resending.\n");
1683 1684 1685
		return 0;
	}

1686 1687 1688 1689
	rxon_assoc.flags = ctx->staging.flags;
	rxon_assoc.filter_flags = ctx->staging.filter_flags;
	rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
	rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
1690 1691
	rxon_assoc.reserved = 0;

S
Stanislaw Gruszka 已提交
1692
	rc = il_send_cmd_sync(il, &cmd);
1693 1694 1695
	if (rc)
		return rc;

1696
	pkt = (struct il_rx_pkt *)cmd.reply_page;
S
Stanislaw Gruszka 已提交
1697
	if (pkt->hdr.flags & IL_CMD_FAILED_MSK) {
1698
		IL_ERR("Bad return from C_RXON_ASSOC command\n");
1699 1700 1701
		rc = -EIO;
	}

S
Stanislaw Gruszka 已提交
1702
	il_free_pages(il, cmd.reply_page);
1703 1704 1705 1706

	return rc;
}

A
Abhijeet Kolekar 已提交
1707
/**
S
Stanislaw Gruszka 已提交
1708
 * il3945_commit_rxon - commit staging_rxon to hardware
A
Abhijeet Kolekar 已提交
1709 1710 1711 1712 1713 1714
 *
 * The RXON command in staging_rxon is committed to the hardware and
 * the active_rxon structure is updated with the new data.  This
 * function correctly transitions out of the RXON_ASSOC_MSK state if
 * a HW tune is required based on the RXON structure changes.
 */
S
Stanislaw Gruszka 已提交
1715
int il3945_commit_rxon(struct il_priv *il, struct il_rxon_context *ctx)
A
Abhijeet Kolekar 已提交
1716 1717
{
	/* cast away the const for active_rxon in this function */
S
Stanislaw Gruszka 已提交
1718 1719
	struct il3945_rxon_cmd *active_rxon = (void *)&ctx->active;
	struct il3945_rxon_cmd *staging_rxon = (void *)&ctx->staging;
A
Abhijeet Kolekar 已提交
1720
	int rc = 0;
1721
	bool new_assoc = !!(staging_rxon->filter_flags & RXON_FILTER_ASSOC_MSK);
A
Abhijeet Kolekar 已提交
1722

S
Stanislaw Gruszka 已提交
1723
	if (test_bit(S_EXIT_PENDING, &il->status))
1724 1725
		return -EINVAL;

S
Stanislaw Gruszka 已提交
1726
	if (!il_is_alive(il))
A
Abhijeet Kolekar 已提交
1727 1728 1729 1730 1731 1732 1733 1734
		return -1;

	/* always get timestamp with Rx frame */
	staging_rxon->flags |= RXON_FLG_TSF2HOST_MSK;

	/* select antenna */
	staging_rxon->flags &=
	    ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
S
Stanislaw Gruszka 已提交
1735
	staging_rxon->flags |= il3945_get_antenna_flags(il);
A
Abhijeet Kolekar 已提交
1736

S
Stanislaw Gruszka 已提交
1737
	rc = il_check_rxon_cmd(il, ctx);
A
Abhijeet Kolekar 已提交
1738
	if (rc) {
1739
		IL_ERR("Invalid RXON configuration.  Not committing.\n");
A
Abhijeet Kolekar 已提交
1740 1741 1742 1743
		return -EINVAL;
	}

	/* If we don't need to send a full RXON, we can use
S
Stanislaw Gruszka 已提交
1744
	 * il3945_rxon_assoc_cmd which is used to reconfigure filter
A
Abhijeet Kolekar 已提交
1745
	 * and other flags for the current radio configuration. */
S
Stanislaw Gruszka 已提交
1746
	if (!il_full_rxon_required(il,
1747
			&il->ctx)) {
S
Stanislaw Gruszka 已提交
1748
		rc = il_send_rxon_assoc(il,
1749
					 &il->ctx);
A
Abhijeet Kolekar 已提交
1750
		if (rc) {
1751
			IL_ERR("Error setting RXON_ASSOC "
A
Abhijeet Kolekar 已提交
1752 1753 1754 1755 1756
				  "configuration (%d).\n", rc);
			return rc;
		}

		memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
1757 1758 1759 1760
		/*
		 * We do not commit tx power settings while channel changing,
		 * do it now if tx power changed.
		 */
S
Stanislaw Gruszka 已提交
1761
		il_set_tx_power(il, il->tx_power_next, false);
A
Abhijeet Kolekar 已提交
1762 1763 1764 1765 1766 1767 1768
		return 0;
	}

	/* If we are currently associated and the new config requires
	 * an RXON_ASSOC and the new config wants the associated mask enabled,
	 * we must clear the associated from the active configuration
	 * before we apply the new config */
1769
	if (il_is_associated(il) && new_assoc) {
1770
		D_INFO("Toggling associated bit on current RXON\n");
A
Abhijeet Kolekar 已提交
1771 1772 1773 1774 1775 1776 1777 1778
		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;

		/*
		 * reserved4 and 5 could have been filled by the iwlcore code.
		 * Let's clear them before pushing to the 3945.
		 */
		active_rxon->reserved4 = 0;
		active_rxon->reserved5 = 0;
1779
		rc = il_send_cmd_pdu(il, C_RXON,
S
Stanislaw Gruszka 已提交
1780
				      sizeof(struct il3945_rxon_cmd),
1781
				      &il->ctx.active);
A
Abhijeet Kolekar 已提交
1782 1783 1784 1785 1786

		/* If the mask clearing failed then we set
		 * active_rxon back to what it was previously */
		if (rc) {
			active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
1787
			IL_ERR("Error clearing ASSOC_MSK on current "
A
Abhijeet Kolekar 已提交
1788 1789 1790
				  "configuration (%d).\n", rc);
			return rc;
		}
S
Stanislaw Gruszka 已提交
1791
		il_clear_ucode_stations(il,
1792
					 &il->ctx);
S
Stanislaw Gruszka 已提交
1793
		il_restore_stations(il,
1794
					 &il->ctx);
A
Abhijeet Kolekar 已提交
1795 1796
	}

1797
	D_INFO("Sending RXON\n"
A
Abhijeet Kolekar 已提交
1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811
		       "* with%s RXON_FILTER_ASSOC_MSK\n"
		       "* channel = %d\n"
		       "* bssid = %pM\n",
		       (new_assoc ? "" : "out"),
		       le16_to_cpu(staging_rxon->channel),
		       staging_rxon->bssid_addr);

	/*
	 * reserved4 and 5 could have been filled by the iwlcore code.
	 * Let's clear them before pushing to the 3945.
	 */
	staging_rxon->reserved4 = 0;
	staging_rxon->reserved5 = 0;

S
Stanislaw Gruszka 已提交
1812
	il_set_rxon_hwcrypto(il, ctx, !il3945_mod_params.sw_crypto);
A
Abhijeet Kolekar 已提交
1813 1814

	/* Apply the new configuration */
1815
	rc = il_send_cmd_pdu(il, C_RXON,
S
Stanislaw Gruszka 已提交
1816
			      sizeof(struct il3945_rxon_cmd),
A
Abhijeet Kolekar 已提交
1817 1818
			      staging_rxon);
	if (rc) {
1819
		IL_ERR("Error setting new configuration (%d).\n", rc);
A
Abhijeet Kolekar 已提交
1820 1821 1822 1823 1824
		return rc;
	}

	memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));

1825
	if (!new_assoc) {
S
Stanislaw Gruszka 已提交
1826
		il_clear_ucode_stations(il,
1827
					 &il->ctx);
S
Stanislaw Gruszka 已提交
1828
		il_restore_stations(il,
1829
					&il->ctx);
1830
	}
A
Abhijeet Kolekar 已提交
1831 1832 1833

	/* If we issue a new RXON command which required a tune then we must
	 * send a new TXPOWER command or we won't be able to Tx any frames */
S
Stanislaw Gruszka 已提交
1834
	rc = il_set_tx_power(il, il->tx_power_next, true);
A
Abhijeet Kolekar 已提交
1835
	if (rc) {
1836
		IL_ERR("Error setting Tx power (%d).\n", rc);
A
Abhijeet Kolekar 已提交
1837 1838 1839 1840
		return rc;
	}

	/* Init the hardware's rate fallback order based on the band */
S
Stanislaw Gruszka 已提交
1841
	rc = il3945_init_hw_rate_table(il);
A
Abhijeet Kolekar 已提交
1842
	if (rc) {
1843
		IL_ERR("Error setting HW rate table: %02X\n", rc);
A
Abhijeet Kolekar 已提交
1844 1845 1846 1847 1848 1849
		return -EIO;
	}

	return 0;
}

Z
Zhu Yi 已提交
1850
/**
S
Stanislaw Gruszka 已提交
1851
 * il3945_reg_txpower_periodic -  called when time to check our temperature.
Z
Zhu Yi 已提交
1852 1853 1854 1855 1856 1857 1858 1859
 *
 * -- reset periodic timer
 * -- see if temp has changed enough to warrant re-calibration ... if so:
 *     -- correct coeffs for temp (can reset temp timer)
 *     -- save this temp as "last",
 *     -- send new set of gain settings to NIC
 * NOTE:  This should continue working, even when we're not associated,
 *   so we can keep our internal table of scan powers current. */
S
Stanislaw Gruszka 已提交
1860
void il3945_reg_txpower_periodic(struct il_priv *il)
Z
Zhu Yi 已提交
1861 1862
{
	/* This will kick in the "brute force"
S
Stanislaw Gruszka 已提交
1863
	 * il3945_hw_reg_comp_txpower_temp() below */
S
Stanislaw Gruszka 已提交
1864
	if (!il3945_is_temp_calib_needed(il))
Z
Zhu Yi 已提交
1865 1866 1867 1868 1869
		goto reschedule;

	/* Set up a new set of temp-adjusted TxPowers, send to NIC.
	 * This is based *only* on current temperature,
	 * ignoring any previous power measurements */
S
Stanislaw Gruszka 已提交
1870
	il3945_hw_reg_comp_txpower_temp(il);
Z
Zhu Yi 已提交
1871 1872

 reschedule:
S
Stanislaw Gruszka 已提交
1873 1874
	queue_delayed_work(il->workqueue,
			   &il->_3945.thermal_periodic, REG_RECALIB_PERIOD * HZ);
Z
Zhu Yi 已提交
1875 1876
}

S
Stanislaw Gruszka 已提交
1877
static void il3945_bg_reg_txpower_periodic(struct work_struct *work)
Z
Zhu Yi 已提交
1878
{
S
Stanislaw Gruszka 已提交
1879
	struct il_priv *il = container_of(work, struct il_priv,
1880
					     _3945.thermal_periodic.work);
Z
Zhu Yi 已提交
1881

S
Stanislaw Gruszka 已提交
1882
	if (test_bit(S_EXIT_PENDING, &il->status))
Z
Zhu Yi 已提交
1883 1884
		return;

S
Stanislaw Gruszka 已提交
1885 1886 1887
	mutex_lock(&il->mutex);
	il3945_reg_txpower_periodic(il);
	mutex_unlock(&il->mutex);
Z
Zhu Yi 已提交
1888 1889 1890
}

/**
S
Stanislaw Gruszka 已提交
1891
 * il3945_hw_reg_get_ch_grp_idx - find the channel-group idx (0-4)
Z
Zhu Yi 已提交
1892 1893 1894 1895 1896 1897 1898 1899 1900
 * 				   for the channel.
 *
 * This function is used when initializing channel-info structs.
 *
 * NOTE: These channel groups do *NOT* match the bands above!
 *	 These channel groups are based on factory-tested channels;
 *	 on A-band, EEPROM's "group frequency" entries represent the top
 *	 channel in each group 1-4.  Group 5 All B/G channels are in group 0.
 */
S
Stanislaw Gruszka 已提交
1901
static u16 il3945_hw_reg_get_ch_grp_idx(struct il_priv *il,
S
Stanislaw Gruszka 已提交
1902
				       const struct il_channel_info *ch_info)
Z
Zhu Yi 已提交
1903
{
S
Stanislaw Gruszka 已提交
1904
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
S
Stanislaw Gruszka 已提交
1905
	struct il3945_eeprom_txpower_group *ch_grp = &eeprom->groups[0];
Z
Zhu Yi 已提交
1906
	u8 group;
S
Stanislaw Gruszka 已提交
1907
	u16 group_idx = 0;	/* based on factory calib frequencies */
Z
Zhu Yi 已提交
1908 1909
	u8 grp_channel;

S
Stanislaw Gruszka 已提交
1910
	/* Find the group idx for the channel ... don't use idx 1(?) */
S
Stanislaw Gruszka 已提交
1911
	if (il_is_channel_a_band(ch_info)) {
Z
Zhu Yi 已提交
1912 1913 1914
		for (group = 1; group < 5; group++) {
			grp_channel = ch_grp[group].group_channel;
			if (ch_info->channel <= grp_channel) {
S
Stanislaw Gruszka 已提交
1915
				group_idx = group;
Z
Zhu Yi 已提交
1916 1917 1918 1919 1920
				break;
			}
		}
		/* group 4 has a few channels *above* its factory cal freq */
		if (group == 5)
S
Stanislaw Gruszka 已提交
1921
			group_idx = 4;
Z
Zhu Yi 已提交
1922
	} else
S
Stanislaw Gruszka 已提交
1923
		group_idx = 0;	/* 2.4 GHz, group 0 */
Z
Zhu Yi 已提交
1924

1925
	D_POWER("Chnl %d mapped to grp %d\n", ch_info->channel,
S
Stanislaw Gruszka 已提交
1926 1927
			group_idx);
	return group_idx;
Z
Zhu Yi 已提交
1928 1929 1930
}

/**
S
Stanislaw Gruszka 已提交
1931
 * il3945_hw_reg_get_matched_power_idx - Interpolate to get nominal idx
Z
Zhu Yi 已提交
1932
 *
S
Stanislaw Gruszka 已提交
1933
 * Interpolate to get nominal (i.e. at factory calibration temperature) idx
Z
Zhu Yi 已提交
1934 1935
 *   into radio/DSP gain settings table for requested power.
 */
S
Stanislaw Gruszka 已提交
1936
static int il3945_hw_reg_get_matched_power_idx(struct il_priv *il,
Z
Zhu Yi 已提交
1937
				       s8 requested_power,
S
Stanislaw Gruszka 已提交
1938
				       s32 setting_idx, s32 *new_idx)
Z
Zhu Yi 已提交
1939
{
S
Stanislaw Gruszka 已提交
1940
	const struct il3945_eeprom_txpower_group *chnl_grp = NULL;
S
Stanislaw Gruszka 已提交
1941
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
S
Stanislaw Gruszka 已提交
1942
	s32 idx0, idx1;
Z
Zhu Yi 已提交
1943 1944
	s32 power = 2 * requested_power;
	s32 i;
S
Stanislaw Gruszka 已提交
1945
	const struct il3945_eeprom_txpower_sample *samples;
Z
Zhu Yi 已提交
1946 1947 1948 1949
	s32 gains0, gains1;
	s32 res;
	s32 denominator;

S
Stanislaw Gruszka 已提交
1950
	chnl_grp = &eeprom->groups[setting_idx];
Z
Zhu Yi 已提交
1951 1952 1953
	samples = chnl_grp->samples;
	for (i = 0; i < 5; i++) {
		if (power == samples[i].power) {
S
Stanislaw Gruszka 已提交
1954
			*new_idx = samples[i].gain_idx;
Z
Zhu Yi 已提交
1955 1956 1957 1958 1959
			return 0;
		}
	}

	if (power > samples[1].power) {
S
Stanislaw Gruszka 已提交
1960 1961
		idx0 = 0;
		idx1 = 1;
Z
Zhu Yi 已提交
1962
	} else if (power > samples[2].power) {
S
Stanislaw Gruszka 已提交
1963 1964
		idx0 = 1;
		idx1 = 2;
Z
Zhu Yi 已提交
1965
	} else if (power > samples[3].power) {
S
Stanislaw Gruszka 已提交
1966 1967
		idx0 = 2;
		idx1 = 3;
Z
Zhu Yi 已提交
1968
	} else {
S
Stanislaw Gruszka 已提交
1969 1970
		idx0 = 3;
		idx1 = 4;
Z
Zhu Yi 已提交
1971 1972
	}

S
Stanislaw Gruszka 已提交
1973
	denominator = (s32) samples[idx1].power - (s32) samples[idx0].power;
Z
Zhu Yi 已提交
1974 1975
	if (denominator == 0)
		return -EINVAL;
S
Stanislaw Gruszka 已提交
1976 1977
	gains0 = (s32) samples[idx0].gain_idx * (1 << 19);
	gains1 = (s32) samples[idx1].gain_idx * (1 << 19);
Z
Zhu Yi 已提交
1978
	res = gains0 + (gains1 - gains0) *
S
Stanislaw Gruszka 已提交
1979
	    ((s32) power - (s32) samples[idx0].power) / denominator +
Z
Zhu Yi 已提交
1980
	    (1 << 18);
S
Stanislaw Gruszka 已提交
1981
	*new_idx = res >> 19;
Z
Zhu Yi 已提交
1982 1983 1984
	return 0;
}

S
Stanislaw Gruszka 已提交
1985
static void il3945_hw_reg_init_channel_groups(struct il_priv *il)
Z
Zhu Yi 已提交
1986 1987
{
	u32 i;
S
Stanislaw Gruszka 已提交
1988
	s32 rate_idx;
S
Stanislaw Gruszka 已提交
1989
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
S
Stanislaw Gruszka 已提交
1990
	const struct il3945_eeprom_txpower_group *group;
Z
Zhu Yi 已提交
1991

1992
	D_POWER("Initializing factory calib info from EEPROM\n");
Z
Zhu Yi 已提交
1993

S
Stanislaw Gruszka 已提交
1994
	for (i = 0; i < IL_NUM_TX_CALIB_GROUPS; i++) {
Z
Zhu Yi 已提交
1995 1996
		s8 *clip_pwrs;	/* table of power levels for each rate */
		s8 satur_pwr;	/* saturation power for each chnl group */
1997
		group = &eeprom->groups[i];
Z
Zhu Yi 已提交
1998 1999 2000

		/* sanity check on factory saturation power value */
		if (group->saturation_power < 40) {
2001
			IL_WARN("Error: saturation power is %d, "
Z
Zhu Yi 已提交
2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015
				    "less than minimum expected 40\n",
				    group->saturation_power);
			return;
		}

		/*
		 * Derive requested power levels for each rate, based on
		 *   hardware capabilities (saturation power for band).
		 * Basic value is 3dB down from saturation, with further
		 *   power reductions for highest 3 data rates.  These
		 *   backoffs provide headroom for high rate modulation
		 *   power peaks, without too much distortion (clipping).
		 */
		/* we'll fill in this array with h/w max power levels */
S
Stanislaw Gruszka 已提交
2016
		clip_pwrs = (s8 *) il->_3945.clip_groups[i].clip_powers;
Z
Zhu Yi 已提交
2017 2018 2019 2020 2021

		/* divide factory saturation power by 2 to find -3dB level */
		satur_pwr = (s8) (group->saturation_power >> 1);

		/* fill in channel group's nominal powers for each rate */
S
Stanislaw Gruszka 已提交
2022 2023 2024
		for (rate_idx = 0;
		     rate_idx < RATE_COUNT_3945; rate_idx++, clip_pwrs++) {
			switch (rate_idx) {
S
Stanislaw Gruszka 已提交
2025
			case RATE_36M_IDX_TBL:
Z
Zhu Yi 已提交
2026 2027 2028 2029 2030
				if (i == 0)	/* B/G */
					*clip_pwrs = satur_pwr;
				else	/* A */
					*clip_pwrs = satur_pwr - 5;
				break;
S
Stanislaw Gruszka 已提交
2031
			case RATE_48M_IDX_TBL:
Z
Zhu Yi 已提交
2032 2033 2034 2035 2036
				if (i == 0)
					*clip_pwrs = satur_pwr - 7;
				else
					*clip_pwrs = satur_pwr - 10;
				break;
S
Stanislaw Gruszka 已提交
2037
			case RATE_54M_IDX_TBL:
Z
Zhu Yi 已提交
2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051
				if (i == 0)
					*clip_pwrs = satur_pwr - 9;
				else
					*clip_pwrs = satur_pwr - 12;
				break;
			default:
				*clip_pwrs = satur_pwr;
				break;
			}
		}
	}
}

/**
S
Stanislaw Gruszka 已提交
2052
 * il3945_txpower_set_from_eeprom - Set channel power info based on EEPROM
Z
Zhu Yi 已提交
2053
 *
S
Stanislaw Gruszka 已提交
2054
 * Second pass (during init) to set up il->channel_info
Z
Zhu Yi 已提交
2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065
 *
 * Set up Tx-power settings in our channel info database for each VALID
 * (for this geo/SKU) channel, at all Tx data rates, based on eeprom values
 * and current temperature.
 *
 * Since this is based on current temperature (at init time), these values may
 * not be valid for very long, but it gives us a starting/default point,
 * and allows us to active (i.e. using Tx) scan.
 *
 * This does *not* write values to NIC, just sets up our internal table.
 */
S
Stanislaw Gruszka 已提交
2066
int il3945_txpower_set_from_eeprom(struct il_priv *il)
Z
Zhu Yi 已提交
2067
{
S
Stanislaw Gruszka 已提交
2068 2069
	struct il_channel_info *ch_info = NULL;
	struct il3945_channel_power_info *pwr_info;
S
Stanislaw Gruszka 已提交
2070
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
S
Stanislaw Gruszka 已提交
2071 2072 2073
	int delta_idx;
	u8 rate_idx;
	u8 scan_tbl_idx;
Z
Zhu Yi 已提交
2074 2075 2076
	const s8 *clip_pwrs;	/* array of power levels for each rate */
	u8 gain, dsp_atten;
	s8 power;
S
Stanislaw Gruszka 已提交
2077
	u8 pwr_idx, base_pwr_idx, a_band;
Z
Zhu Yi 已提交
2078 2079 2080 2081 2082
	u8 i;
	int temperature;

	/* save temperature reference,
	 *   so we can determine next time to calibrate */
S
Stanislaw Gruszka 已提交
2083 2084
	temperature = il3945_hw_reg_txpower_get_temperature(il);
	il->last_temperature = temperature;
Z
Zhu Yi 已提交
2085

S
Stanislaw Gruszka 已提交
2086
	il3945_hw_reg_init_channel_groups(il);
Z
Zhu Yi 已提交
2087 2088

	/* initialize Tx power info for each and every channel, 2.4 and 5.x */
S
Stanislaw Gruszka 已提交
2089
	for (i = 0, ch_info = il->channel_info; i < il->channel_count;
Z
Zhu Yi 已提交
2090
	     i++, ch_info++) {
S
Stanislaw Gruszka 已提交
2091 2092
		a_band = il_is_channel_a_band(ch_info);
		if (!il_is_channel_valid(ch_info))
Z
Zhu Yi 已提交
2093 2094
			continue;

S
Stanislaw Gruszka 已提交
2095 2096 2097
		/* find this channel's channel group (*not* "band") idx */
		ch_info->group_idx =
			il3945_hw_reg_get_ch_grp_idx(il, ch_info);
Z
Zhu Yi 已提交
2098 2099

		/* Get this chnlgrp's rate->max/clip-powers table */
S
Stanislaw Gruszka 已提交
2100
		clip_pwrs = il->_3945.clip_groups[ch_info->group_idx].clip_powers;
Z
Zhu Yi 已提交
2101

S
Stanislaw Gruszka 已提交
2102
		/* calculate power idx *adjustment* value according to
Z
Zhu Yi 已提交
2103
		 *  diff between current temperature and factory temperature */
S
Stanislaw Gruszka 已提交
2104 2105
		delta_idx = il3945_hw_reg_adjust_power_by_temp(temperature,
				eeprom->groups[ch_info->group_idx].
Z
Zhu Yi 已提交
2106 2107
				temperature);

S
Stanislaw Gruszka 已提交
2108 2109
		D_POWER("Delta idx for channel %d: %d [%d]\n",
				ch_info->channel, delta_idx, temperature +
S
Stanislaw Gruszka 已提交
2110
				IL_TEMP_CONVERT);
Z
Zhu Yi 已提交
2111 2112

		/* set tx power value for all OFDM rates */
S
Stanislaw Gruszka 已提交
2113 2114
		for (rate_idx = 0; rate_idx < IL_OFDM_RATES;
		     rate_idx++) {
2115
			s32 uninitialized_var(power_idx);
Z
Zhu Yi 已提交
2116 2117 2118 2119 2120
			int rc;

			/* use channel group's clip-power table,
			 *   but don't exceed channel's max power */
			s8 pwr = min(ch_info->max_power_avg,
S
Stanislaw Gruszka 已提交
2121
				     clip_pwrs[rate_idx]);
Z
Zhu Yi 已提交
2122

S
Stanislaw Gruszka 已提交
2123
			pwr_info = &ch_info->power_info[rate_idx];
Z
Zhu Yi 已提交
2124 2125

			/* get base (i.e. at factory-measured temperature)
S
Stanislaw Gruszka 已提交
2126 2127 2128
			 *    power table idx for this rate's power */
			rc = il3945_hw_reg_get_matched_power_idx(il, pwr,
							 ch_info->group_idx,
Z
Zhu Yi 已提交
2129 2130
							 &power_idx);
			if (rc) {
S
Stanislaw Gruszka 已提交
2131
				IL_ERR("Invalid power idx\n");
Z
Zhu Yi 已提交
2132 2133
				return rc;
			}
S
Stanislaw Gruszka 已提交
2134
			pwr_info->base_power_idx = (u8) power_idx;
Z
Zhu Yi 已提交
2135 2136

			/* temperature compensate */
S
Stanislaw Gruszka 已提交
2137
			power_idx += delta_idx;
Z
Zhu Yi 已提交
2138 2139

			/* stay within range of gain table */
S
Stanislaw Gruszka 已提交
2140
			power_idx = il3945_hw_reg_fix_power_idx(power_idx);
Z
Zhu Yi 已提交
2141

S
Stanislaw Gruszka 已提交
2142
			/* fill 1 OFDM rate's il3945_channel_power_info struct */
Z
Zhu Yi 已提交
2143
			pwr_info->requested_power = pwr;
S
Stanislaw Gruszka 已提交
2144
			pwr_info->power_table_idx = (u8) power_idx;
Z
Zhu Yi 已提交
2145 2146 2147 2148 2149 2150 2151
			pwr_info->tpc.tx_gain =
			    power_gain_table[a_band][power_idx].tx_gain;
			pwr_info->tpc.dsp_atten =
			    power_gain_table[a_band][power_idx].dsp_atten;
		}

		/* set tx power for CCK rates, based on OFDM 12 Mbit settings*/
S
Stanislaw Gruszka 已提交
2152
		pwr_info = &ch_info->power_info[RATE_12M_IDX_TBL];
Z
Zhu Yi 已提交
2153
		power = pwr_info->requested_power +
S
Stanislaw Gruszka 已提交
2154
			IL_CCK_FROM_OFDM_POWER_DIFF;
S
Stanislaw Gruszka 已提交
2155
		pwr_idx = pwr_info->power_table_idx +
S
Stanislaw Gruszka 已提交
2156
			IL_CCK_FROM_OFDM_IDX_DIFF;
S
Stanislaw Gruszka 已提交
2157
		base_pwr_idx = pwr_info->base_power_idx +
S
Stanislaw Gruszka 已提交
2158
			IL_CCK_FROM_OFDM_IDX_DIFF;
Z
Zhu Yi 已提交
2159 2160

		/* stay within table range */
S
Stanislaw Gruszka 已提交
2161 2162 2163
		pwr_idx = il3945_hw_reg_fix_power_idx(pwr_idx);
		gain = power_gain_table[a_band][pwr_idx].tx_gain;
		dsp_atten = power_gain_table[a_band][pwr_idx].dsp_atten;
Z
Zhu Yi 已提交
2164

S
Stanislaw Gruszka 已提交
2165
		/* fill each CCK rate's il3945_channel_power_info structure
Z
Zhu Yi 已提交
2166 2167
		 * NOTE:  All CCK-rate Txpwrs are the same for a given chnl!
		 * NOTE:  CCK rates start at end of OFDM rates! */
S
Stanislaw Gruszka 已提交
2168 2169 2170
		for (rate_idx = 0;
		     rate_idx < IL_CCK_RATES; rate_idx++) {
			pwr_info = &ch_info->power_info[rate_idx+IL_OFDM_RATES];
Z
Zhu Yi 已提交
2171
			pwr_info->requested_power = power;
S
Stanislaw Gruszka 已提交
2172 2173
			pwr_info->power_table_idx = pwr_idx;
			pwr_info->base_power_idx = base_pwr_idx;
Z
Zhu Yi 已提交
2174 2175 2176 2177 2178
			pwr_info->tpc.tx_gain = gain;
			pwr_info->tpc.dsp_atten = dsp_atten;
		}

		/* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */
S
Stanislaw Gruszka 已提交
2179 2180 2181
		for (scan_tbl_idx = 0;
		     scan_tbl_idx < IL_NUM_SCAN_RATES; scan_tbl_idx++) {
			s32 actual_idx = (scan_tbl_idx == 0) ?
S
Stanislaw Gruszka 已提交
2182
				RATE_1M_IDX_TBL : RATE_6M_IDX_TBL;
S
Stanislaw Gruszka 已提交
2183 2184
			il3945_hw_reg_set_scan_power(il, scan_tbl_idx,
				actual_idx, clip_pwrs, ch_info, a_band);
Z
Zhu Yi 已提交
2185 2186 2187 2188 2189 2190
		}
	}

	return 0;
}

S
Stanislaw Gruszka 已提交
2191
int il3945_hw_rxq_stop(struct il_priv *il)
Z
Zhu Yi 已提交
2192 2193 2194
{
	int rc;

2195 2196
	il_wr(il, FH39_RCSR_CONFIG(0), 0);
	rc = il_poll_bit(il, FH39_RSSR_STATUS,
2197
			FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
Z
Zhu Yi 已提交
2198
	if (rc < 0)
2199
		IL_ERR("Can't stop Rx DMA.\n");
Z
Zhu Yi 已提交
2200 2201 2202 2203

	return 0;
}

S
Stanislaw Gruszka 已提交
2204
int il3945_hw_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq)
Z
Zhu Yi 已提交
2205 2206 2207
{
	int txq_id = txq->q.id;

S
Stanislaw Gruszka 已提交
2208
	struct il3945_shared *shared_data = il->_3945.shared_virt;
Z
Zhu Yi 已提交
2209 2210 2211

	shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr);

2212 2213
	il_wr(il, FH39_CBCC_CTRL(txq_id), 0);
	il_wr(il, FH39_CBCC_BASE(txq_id), 0);
2214

2215
	il_wr(il, FH39_TCSR_CONFIG(txq_id),
2216 2217 2218 2219 2220
		FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT |
		FH39_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF |
		FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD |
		FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL |
		FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE);
Z
Zhu Yi 已提交
2221 2222

	/* fake read to flush all prev. writes */
2223
	_il_rd(il, FH39_TSSR_CBB_BASE);
Z
Zhu Yi 已提交
2224 2225 2226 2227

	return 0;
}

K
Kolekar, Abhijeet 已提交
2228 2229 2230
/*
 * HCMD utils
 */
S
Stanislaw Gruszka 已提交
2231
static u16 il3945_get_hcmd_size(u8 cmd_id, u16 len)
K
Kolekar, Abhijeet 已提交
2232 2233
{
	switch (cmd_id) {
2234
	case C_RXON:
S
Stanislaw Gruszka 已提交
2235
		return sizeof(struct il3945_rxon_cmd);
2236
	case C_POWER_TBL:
S
Stanislaw Gruszka 已提交
2237
		return sizeof(struct il3945_powertable_cmd);
K
Kolekar, Abhijeet 已提交
2238 2239 2240 2241 2242
	default:
		return len;
	}
}

2243

S
Stanislaw Gruszka 已提交
2244
static u16 il3945_build_addsta_hcmd(const struct il_addsta_cmd *cmd,
2245
								u8 *data)
2246
{
S
Stanislaw Gruszka 已提交
2247
	struct il3945_addsta_cmd *addsta = (struct il3945_addsta_cmd *)data;
2248 2249
	addsta->mode = cmd->mode;
	memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify));
S
Stanislaw Gruszka 已提交
2250
	memcpy(&addsta->key, &cmd->key, sizeof(struct il4965_keyinfo));
2251 2252 2253 2254 2255 2256 2257 2258
	addsta->station_flags = cmd->station_flags;
	addsta->station_flags_msk = cmd->station_flags_msk;
	addsta->tid_disable_tx = cpu_to_le16(0);
	addsta->rate_n_flags = cmd->rate_n_flags;
	addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid;
	addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid;
	addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn;

S
Stanislaw Gruszka 已提交
2259
	return (u16)sizeof(struct il3945_addsta_cmd);
2260 2261
}

S
Stanislaw Gruszka 已提交
2262
static int il3945_add_bssid_station(struct il_priv *il,
2263 2264
				     const u8 *addr, u8 *sta_id_r)
{
2265
	struct il_rxon_context *ctx = &il->ctx;
2266 2267 2268 2269 2270
	int ret;
	u8 sta_id;
	unsigned long flags;

	if (sta_id_r)
S
Stanislaw Gruszka 已提交
2271
		*sta_id_r = IL_INVALID_STATION;
2272

S
Stanislaw Gruszka 已提交
2273
	ret = il_add_station_common(il, ctx, addr, 0, NULL, &sta_id);
2274
	if (ret) {
2275
		IL_ERR("Unable to add station %pM\n", addr);
2276 2277 2278 2279 2280 2281
		return ret;
	}

	if (sta_id_r)
		*sta_id_r = sta_id;

S
Stanislaw Gruszka 已提交
2282 2283 2284
	spin_lock_irqsave(&il->sta_lock, flags);
	il->stations[sta_id].used |= IL_STA_LOCAL;
	spin_unlock_irqrestore(&il->sta_lock, flags);
2285 2286 2287

	return 0;
}
S
Stanislaw Gruszka 已提交
2288
static int il3945_manage_ibss_station(struct il_priv *il,
2289 2290
				       struct ieee80211_vif *vif, bool add)
{
S
Stanislaw Gruszka 已提交
2291
	struct il_vif_priv *vif_priv = (void *)vif->drv_priv;
2292 2293 2294
	int ret;

	if (add) {
S
Stanislaw Gruszka 已提交
2295
		ret = il3945_add_bssid_station(il, vif->bss_conf.bssid,
2296
						&vif_priv->ibss_bssid_sta_id);
2297 2298 2299
		if (ret)
			return ret;

S
Stanislaw Gruszka 已提交
2300 2301
		il3945_sync_sta(il, vif_priv->ibss_bssid_sta_id,
				 (il->band == IEEE80211_BAND_5GHZ) ?
S
Stanislaw Gruszka 已提交
2302
				 RATE_6M_PLCP : RATE_1M_PLCP);
S
Stanislaw Gruszka 已提交
2303
		il3945_rate_scale_init(il->hw, vif_priv->ibss_bssid_sta_id);
2304 2305 2306 2307

		return 0;
	}

S
Stanislaw Gruszka 已提交
2308
	return il_remove_station(il, vif_priv->ibss_bssid_sta_id,
J
Johannes Berg 已提交
2309
				  vif->bss_conf.bssid);
2310
}
2311

Z
Zhu Yi 已提交
2312
/**
S
Stanislaw Gruszka 已提交
2313
 * il3945_init_hw_rate_table - Initialize the hardware rate fallback table
Z
Zhu Yi 已提交
2314
 */
S
Stanislaw Gruszka 已提交
2315
int il3945_init_hw_rate_table(struct il_priv *il)
Z
Zhu Yi 已提交
2316
{
S
Stanislaw Gruszka 已提交
2317
	int rc, i, idx, prev_idx;
S
Stanislaw Gruszka 已提交
2318
	struct il3945_rate_scaling_cmd rate_cmd = {
Z
Zhu Yi 已提交
2319 2320
		.reserved = {0, 0, 0},
	};
S
Stanislaw Gruszka 已提交
2321
	struct il3945_rate_scaling_info *table = rate_cmd.table;
Z
Zhu Yi 已提交
2322

S
Stanislaw Gruszka 已提交
2323
	for (i = 0; i < ARRAY_SIZE(il3945_rates); i++) {
S
Stanislaw Gruszka 已提交
2324
		idx = il3945_rates[i].table_rs_idx;
2325

S
Stanislaw Gruszka 已提交
2326
		table[idx].rate_n_flags =
S
Stanislaw Gruszka 已提交
2327
			il3945_hw_set_rate_n_flags(il3945_rates[i].plcp, 0);
S
Stanislaw Gruszka 已提交
2328 2329 2330 2331
		table[idx].try_cnt = il->retry_rate;
		prev_idx = il3945_get_prev_ieee_rate(i);
		table[idx].next_rate_idx =
				il3945_rates[prev_idx].table_rs_idx;
Z
Zhu Yi 已提交
2332 2333
	}

S
Stanislaw Gruszka 已提交
2334
	switch (il->band) {
2335
	case IEEE80211_BAND_5GHZ:
2336
		D_RATE("Select A mode rate scale\n");
Z
Zhu Yi 已提交
2337 2338
		/* If one of the following CCK rates is used,
		 * have it fall back to the 6M OFDM rate */
S
Stanislaw Gruszka 已提交
2339 2340
		for (i = RATE_1M_IDX_TBL;
			i <= RATE_11M_IDX_TBL; i++)
S
Stanislaw Gruszka 已提交
2341 2342
			table[i].next_rate_idx =
			  il3945_rates[IL_FIRST_OFDM_RATE].table_rs_idx;
Z
Zhu Yi 已提交
2343 2344

		/* Don't fall back to CCK rates */
S
Stanislaw Gruszka 已提交
2345 2346
		table[RATE_12M_IDX_TBL].next_rate_idx =
						RATE_9M_IDX_TBL;
Z
Zhu Yi 已提交
2347 2348

		/* Don't drop out of OFDM rates */
S
Stanislaw Gruszka 已提交
2349
		table[RATE_6M_IDX_TBL].next_rate_idx =
S
Stanislaw Gruszka 已提交
2350
		    il3945_rates[IL_FIRST_OFDM_RATE].table_rs_idx;
Z
Zhu Yi 已提交
2351 2352
		break;

2353
	case IEEE80211_BAND_2GHZ:
2354
		D_RATE("Select B/G mode rate scale\n");
Z
Zhu Yi 已提交
2355 2356 2357
		/* If an OFDM rate is used, have it fall back to the
		 * 1M CCK rates */

S
Stanislaw Gruszka 已提交
2358
		if (!(il->_3945.sta_supp_rates & IL_OFDM_RATES_MASK) &&
2359
		    il_is_associated(il)) {
2360

S
Stanislaw Gruszka 已提交
2361
			idx = IL_FIRST_CCK_RATE;
S
Stanislaw Gruszka 已提交
2362 2363
			for (i = RATE_6M_IDX_TBL;
			     i <= RATE_54M_IDX_TBL; i++)
S
Stanislaw Gruszka 已提交
2364 2365
				table[i].next_rate_idx =
					il3945_rates[idx].table_rs_idx;
2366

S
Stanislaw Gruszka 已提交
2367
			idx = RATE_11M_IDX_TBL;
2368
			/* CCK shouldn't fall back to OFDM... */
S
Stanislaw Gruszka 已提交
2369
			table[idx].next_rate_idx = RATE_5M_IDX_TBL;
2370
		}
Z
Zhu Yi 已提交
2371 2372 2373
		break;

	default:
2374
		WARN_ON(1);
Z
Zhu Yi 已提交
2375 2376 2377 2378 2379
		break;
	}

	/* Update the rate scaling for control frame Tx */
	rate_cmd.table_id = 0;
2380
	rc = il_send_cmd_pdu(il, C_RATE_SCALE, sizeof(rate_cmd),
Z
Zhu Yi 已提交
2381 2382 2383 2384 2385 2386
			      &rate_cmd);
	if (rc)
		return rc;

	/* Update the rate scaling for data frame Tx */
	rate_cmd.table_id = 1;
2387
	return il_send_cmd_pdu(il, C_RATE_SCALE, sizeof(rate_cmd),
Z
Zhu Yi 已提交
2388 2389 2390
				&rate_cmd);
}

2391
/* Called when initializing driver */
S
Stanislaw Gruszka 已提交
2392
int il3945_hw_set_hw_params(struct il_priv *il)
Z
Zhu Yi 已提交
2393
{
S
Stanislaw Gruszka 已提交
2394
	memset((void *)&il->hw_params, 0,
S
Stanislaw Gruszka 已提交
2395
	       sizeof(struct il_hw_params));
Z
Zhu Yi 已提交
2396

S
Stanislaw Gruszka 已提交
2397 2398
	il->_3945.shared_virt =
		dma_alloc_coherent(&il->pci_dev->dev,
S
Stanislaw Gruszka 已提交
2399
				   sizeof(struct il3945_shared),
S
Stanislaw Gruszka 已提交
2400 2401
				   &il->_3945.shared_phys, GFP_KERNEL);
	if (!il->_3945.shared_virt) {
2402
		IL_ERR("failed to allocate pci memory\n");
Z
Zhu Yi 已提交
2403 2404 2405
		return -ENOMEM;
	}

2406
	/* Assign number of Usable TX queues */
S
Stanislaw Gruszka 已提交
2407
	il->hw_params.max_txq_num = il->cfg->base_params->num_of_queues;
2408

S
Stanislaw Gruszka 已提交
2409 2410 2411 2412
	il->hw_params.tfd_size = sizeof(struct il3945_tfd);
	il->hw_params.rx_page_order = get_order(IL_RX_BUF_SIZE_3K);
	il->hw_params.max_rxq_size = RX_QUEUE_SIZE;
	il->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
2413
	il->hw_params.max_stations = IL3945_STATION_COUNT;
2414
	il->ctx.bcast_sta_id = IL3945_BROADCAST_ID;
2415

S
Stanislaw Gruszka 已提交
2416
	il->sta_key_max_num = STA_KEY_MAX_NUM;
2417

S
Stanislaw Gruszka 已提交
2418
	il->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
2419 2420
	il->hw_params.max_beacon_itrvl = IL39_MAX_UCODE_BEACON_INTERVAL;
	il->hw_params.beacon_time_tsf_bits = IL3945_EXT_BEACON_TIME_POS;
2421

Z
Zhu Yi 已提交
2422 2423 2424
	return 0;
}

S
Stanislaw Gruszka 已提交
2425
unsigned int il3945_hw_get_beacon_cmd(struct il_priv *il,
S
Stanislaw Gruszka 已提交
2426
			  struct il3945_frame *frame, u8 rate)
Z
Zhu Yi 已提交
2427
{
S
Stanislaw Gruszka 已提交
2428
	struct il3945_tx_beacon_cmd *tx_beacon_cmd;
Z
Zhu Yi 已提交
2429 2430
	unsigned int frame_size;

S
Stanislaw Gruszka 已提交
2431
	tx_beacon_cmd = (struct il3945_tx_beacon_cmd *)&frame->u;
Z
Zhu Yi 已提交
2432 2433
	memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));

2434
	tx_beacon_cmd->tx.sta_id =
2435
		il->ctx.bcast_sta_id;
Z
Zhu Yi 已提交
2436 2437
	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;

S
Stanislaw Gruszka 已提交
2438
	frame_size = il3945_fill_beacon_frame(il,
Z
Zhu Yi 已提交
2439 2440 2441 2442 2443 2444 2445 2446 2447 2448
				tx_beacon_cmd->frame,
				sizeof(frame->u) - sizeof(*tx_beacon_cmd));

	BUG_ON(frame_size > MAX_MPDU_SIZE);
	tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);

	tx_beacon_cmd->tx.rate = rate;
	tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK |
				      TX_CMD_FLG_TSF_MSK);

S
Stanislaw Gruszka 已提交
2449
	/* supp_rates[0] == OFDM start at IL_FIRST_OFDM_RATE*/
2450
	tx_beacon_cmd->tx.supp_rates[0] =
S
Stanislaw Gruszka 已提交
2451
		(IL_OFDM_BASIC_RATES_MASK >> IL_FIRST_OFDM_RATE) & 0xFF;
2452

Z
Zhu Yi 已提交
2453
	tx_beacon_cmd->tx.supp_rates[1] =
S
Stanislaw Gruszka 已提交
2454
		(IL_CCK_BASIC_RATES_MASK & 0xF);
Z
Zhu Yi 已提交
2455

S
Stanislaw Gruszka 已提交
2456
	return sizeof(struct il3945_tx_beacon_cmd) + frame_size;
Z
Zhu Yi 已提交
2457 2458
}

2459
void il3945_hw_handler_setup(struct il_priv *il)
Z
Zhu Yi 已提交
2460
{
S
Stanislaw Gruszka 已提交
2461 2462
	il->handlers[C_TX] = il3945_hdl_tx;
	il->handlers[N_3945_RX] = il3945_hdl_rx;
Z
Zhu Yi 已提交
2463 2464
}

S
Stanislaw Gruszka 已提交
2465
void il3945_hw_setup_deferred_work(struct il_priv *il)
Z
Zhu Yi 已提交
2466
{
S
Stanislaw Gruszka 已提交
2467
	INIT_DELAYED_WORK(&il->_3945.thermal_periodic,
S
Stanislaw Gruszka 已提交
2468
			  il3945_bg_reg_txpower_periodic);
Z
Zhu Yi 已提交
2469 2470
}

S
Stanislaw Gruszka 已提交
2471
void il3945_hw_cancel_deferred_work(struct il_priv *il)
Z
Zhu Yi 已提交
2472
{
S
Stanislaw Gruszka 已提交
2473
	cancel_delayed_work(&il->_3945.thermal_periodic);
Z
Zhu Yi 已提交
2474 2475
}

K
Kolekar, Abhijeet 已提交
2476
/* check contents of special bootstrap uCode SRAM */
S
Stanislaw Gruszka 已提交
2477
static int il3945_verify_bsm(struct il_priv *il)
K
Kolekar, Abhijeet 已提交
2478
 {
S
Stanislaw Gruszka 已提交
2479 2480
	__le32 *image = il->ucode_boot.v_addr;
	u32 len = il->ucode_boot.len;
K
Kolekar, Abhijeet 已提交
2481 2482 2483
	u32 reg;
	u32 val;

2484
	D_INFO("Begin verify bsm\n");
K
Kolekar, Abhijeet 已提交
2485 2486

	/* verify BSM SRAM contents */
2487
	val = il_rd_prph(il, BSM_WR_DWCOUNT_REG);
K
Kolekar, Abhijeet 已提交
2488 2489 2490
	for (reg = BSM_SRAM_LOWER_BOUND;
	     reg < BSM_SRAM_LOWER_BOUND + len;
	     reg += sizeof(u32), image++) {
2491
		val = il_rd_prph(il, reg);
K
Kolekar, Abhijeet 已提交
2492
		if (val != le32_to_cpu(*image)) {
2493
			IL_ERR("BSM uCode verification failed at "
K
Kolekar, Abhijeet 已提交
2494 2495 2496 2497 2498 2499 2500 2501
				  "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;
		}
	}

2502
	D_INFO("BSM bootstrap uCode image OK\n");
K
Kolekar, Abhijeet 已提交
2503 2504 2505 2506

	return 0;
}

2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521

/******************************************************************************
 *
 * EEPROM related functions
 *
 ******************************************************************************/

/*
 * Clear the OWNER_MSK, to establish driver (instead of uCode running on
 * embedded controller) as EEPROM reader; each read is a series of pulses
 * to/from the EEPROM chip, not a single event, so even reads could conflict
 * if they weren't arbitrated by some ownership mechanism.  Here, the driver
 * simply claims ownership, which should be safe when this function is called
 * (i.e. before loading uCode!).
 */
S
Stanislaw Gruszka 已提交
2522
static int il3945_eeprom_acquire_semaphore(struct il_priv *il)
2523
{
S
Stanislaw Gruszka 已提交
2524
	_il_clear_bit(il, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
2525 2526 2527 2528
	return 0;
}


S
Stanislaw Gruszka 已提交
2529
static void il3945_eeprom_release_semaphore(struct il_priv *il)
2530 2531 2532 2533
{
	return;
}

K
Kolekar, Abhijeet 已提交
2534
 /**
S
Stanislaw Gruszka 已提交
2535
  * il3945_load_bsm - Load bootstrap instructions
K
Kolekar, Abhijeet 已提交
2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565
  *
  * 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.
  */
S
Stanislaw Gruszka 已提交
2566
static int il3945_load_bsm(struct il_priv *il)
K
Kolekar, Abhijeet 已提交
2567
{
S
Stanislaw Gruszka 已提交
2568 2569
	__le32 *image = il->ucode_boot.v_addr;
	u32 len = il->ucode_boot.len;
K
Kolekar, Abhijeet 已提交
2570 2571 2572 2573 2574 2575 2576 2577 2578
	dma_addr_t pinst;
	dma_addr_t pdata;
	u32 inst_len;
	u32 data_len;
	int rc;
	int i;
	u32 done;
	u32 reg_offset;

2579
	D_INFO("Begin load bsm\n");
K
Kolekar, Abhijeet 已提交
2580 2581

	/* make sure bootstrap program is no larger than BSM's SRAM size */
2582
	if (len > IL39_MAX_BSM_SIZE)
K
Kolekar, Abhijeet 已提交
2583 2584 2585 2586
		return -EINVAL;

	/* Tell bootstrap uCode where to find the "Initialize" uCode
	*   in host DRAM ... host DRAM physical address bits 31:0 for 3945.
S
Stanislaw Gruszka 已提交
2587
	* NOTE:  il3945_initialize_alive_start() will replace these values,
K
Kolekar, Abhijeet 已提交
2588 2589
	*        after the "initialize" uCode has run, to point to
	*        runtime/protocol instructions and backup data cache. */
S
Stanislaw Gruszka 已提交
2590 2591 2592 2593
	pinst = il->ucode_init.p_addr;
	pdata = il->ucode_init_data.p_addr;
	inst_len = il->ucode_init.len;
	data_len = il->ucode_init_data.len;
K
Kolekar, Abhijeet 已提交
2594

2595 2596 2597 2598
	il_wr_prph(il, BSM_DRAM_INST_PTR_REG, pinst);
	il_wr_prph(il, BSM_DRAM_DATA_PTR_REG, pdata);
	il_wr_prph(il, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
	il_wr_prph(il, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
K
Kolekar, Abhijeet 已提交
2599 2600 2601 2602 2603

	/* 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++)
2604
		_il_wr_prph(il, reg_offset,
K
Kolekar, Abhijeet 已提交
2605 2606
					  le32_to_cpu(*image));

S
Stanislaw Gruszka 已提交
2607
	rc = il3945_verify_bsm(il);
M
Mohamed Abbas 已提交
2608
	if (rc)
K
Kolekar, Abhijeet 已提交
2609 2610 2611
		return rc;

	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
2612 2613
	il_wr_prph(il, BSM_WR_MEM_SRC_REG, 0x0);
	il_wr_prph(il, BSM_WR_MEM_DST_REG,
2614
				 IL39_RTC_INST_LOWER_BOUND);
2615
	il_wr_prph(il, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
K
Kolekar, Abhijeet 已提交
2616 2617 2618

	/* Load bootstrap code into instruction SRAM now,
	 *   to prepare to load "initialize" uCode */
2619
	il_wr_prph(il, BSM_WR_CTRL_REG,
K
Kolekar, Abhijeet 已提交
2620 2621 2622 2623
		BSM_WR_CTRL_REG_BIT_START);

	/* Wait for load of bootstrap uCode to finish */
	for (i = 0; i < 100; i++) {
2624
		done = il_rd_prph(il, BSM_WR_CTRL_REG);
K
Kolekar, Abhijeet 已提交
2625 2626 2627 2628 2629
		if (!(done & BSM_WR_CTRL_REG_BIT_START))
			break;
		udelay(10);
	}
	if (i < 100)
2630
		D_INFO("BSM write complete, poll %d iterations\n", i);
K
Kolekar, Abhijeet 已提交
2631
	else {
2632
		IL_ERR("BSM write did not complete!\n");
K
Kolekar, Abhijeet 已提交
2633 2634 2635 2636 2637
		return -EIO;
	}

	/* Enable future boot loads whenever power management unit triggers it
	 *   (e.g. when powering back up after power-save shutdown) */
2638
	il_wr_prph(il, BSM_WR_CTRL_REG,
K
Kolekar, Abhijeet 已提交
2639 2640 2641 2642 2643
		BSM_WR_CTRL_REG_BIT_START_EN);

	return 0;
}

S
Stanislaw Gruszka 已提交
2644 2645 2646
static struct il_hcmd_ops il3945_hcmd = {
	.rxon_assoc = il3945_send_rxon_assoc,
	.commit_rxon = il3945_commit_rxon,
2647 2648
};

S
Stanislaw Gruszka 已提交
2649 2650 2651 2652 2653 2654
static struct il_lib_ops il3945_lib = {
	.txq_attach_buf_to_tfd = il3945_hw_txq_attach_buf_to_tfd,
	.txq_free_tfd = il3945_hw_txq_free_tfd,
	.txq_init = il3945_hw_tx_queue_init,
	.load_ucode = il3945_load_bsm,
	.dump_nic_error_log = il3945_dump_nic_error_log,
K
Kolekar, Abhijeet 已提交
2655
	.apm_ops = {
S
Stanislaw Gruszka 已提交
2656 2657
		.init = il3945_apm_init,
		.config = il3945_nic_config,
K
Kolekar, Abhijeet 已提交
2658
	},
2659 2660 2661 2662 2663 2664 2665
	.eeprom_ops = {
		.regulatory_bands = {
			EEPROM_REGULATORY_BAND_1_CHANNELS,
			EEPROM_REGULATORY_BAND_2_CHANNELS,
			EEPROM_REGULATORY_BAND_3_CHANNELS,
			EEPROM_REGULATORY_BAND_4_CHANNELS,
			EEPROM_REGULATORY_BAND_5_CHANNELS,
2666 2667
			EEPROM_REGULATORY_BAND_NO_HT40,
			EEPROM_REGULATORY_BAND_NO_HT40,
2668
		},
S
Stanislaw Gruszka 已提交
2669 2670
		.acquire_semaphore = il3945_eeprom_acquire_semaphore,
		.release_semaphore = il3945_eeprom_release_semaphore,
2671
	},
S
Stanislaw Gruszka 已提交
2672 2673
	.send_tx_power	= il3945_send_tx_power,
	.is_valid_rtc_data_addr = il3945_hw_valid_rtc_data_addr,
A
Abhijeet Kolekar 已提交
2674 2675

	.debugfs_ops = {
S
Stanislaw Gruszka 已提交
2676 2677 2678
		.rx_stats_read = il3945_ucode_rx_stats_read,
		.tx_stats_read = il3945_ucode_tx_stats_read,
		.general_stats_read = il3945_ucode_general_stats_read,
A
Abhijeet Kolekar 已提交
2679
	},
K
Kolekar, Abhijeet 已提交
2680 2681
};

S
Stanislaw Gruszka 已提交
2682 2683 2684 2685
static const struct il_legacy_ops il3945_legacy_ops = {
	.post_associate = il3945_post_associate,
	.config_ap = il3945_config_ap,
	.manage_ibss_station = il3945_manage_ibss_station,
2686 2687
};

S
Stanislaw Gruszka 已提交
2688 2689 2690 2691 2692
static struct il_hcmd_utils_ops il3945_hcmd_utils = {
	.get_hcmd_size = il3945_get_hcmd_size,
	.build_addsta_hcmd = il3945_build_addsta_hcmd,
	.request_scan = il3945_request_scan,
	.post_scan = il3945_post_scan,
K
Kolekar, Abhijeet 已提交
2693 2694
};

S
Stanislaw Gruszka 已提交
2695 2696 2697 2698 2699 2700 2701
static const struct il_ops il3945_ops = {
	.lib = &il3945_lib,
	.hcmd = &il3945_hcmd,
	.utils = &il3945_hcmd_utils,
	.led = &il3945_led_ops,
	.legacy = &il3945_legacy_ops,
	.ieee80211_ops = &il3945_hw_ops,
K
Kolekar, Abhijeet 已提交
2702 2703
};

S
Stanislaw Gruszka 已提交
2704
static struct il_base_params il3945_base_params = {
2705 2706
	.eeprom_size = IL3945_EEPROM_IMG_SIZE,
	.num_of_queues = IL39_NUM_QUEUES,
2707 2708 2709
	.pll_cfg_val = CSR39_ANA_PLL_CFG_VAL,
	.set_l0s = false,
	.use_bsm = true,
2710
	.led_compensation = 64,
S
Stanislaw Gruszka 已提交
2711
	.wd_timeout = IL_DEF_WD_TIMEOUT,
T
Tomas Winkler 已提交
2712 2713
};

S
Stanislaw Gruszka 已提交
2714
static struct il_cfg il3945_bg_cfg = {
2715
	.name = "3945BG",
2716 2717 2718
	.fw_name_pre = IL3945_FW_PRE,
	.ucode_api_max = IL3945_UCODE_API_MAX,
	.ucode_api_min = IL3945_UCODE_API_MIN,
S
Stanislaw Gruszka 已提交
2719
	.sku = IL_SKU_G,
2720
	.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
S
Stanislaw Gruszka 已提交
2721 2722 2723 2724
	.ops = &il3945_ops,
	.mod_params = &il3945_mod_params,
	.base_params = &il3945_base_params,
	.led_mode = IL_LED_BLINK,
2725 2726
};

S
Stanislaw Gruszka 已提交
2727
static struct il_cfg il3945_abg_cfg = {
T
Tomas Winkler 已提交
2728
	.name = "3945ABG",
2729 2730 2731
	.fw_name_pre = IL3945_FW_PRE,
	.ucode_api_max = IL3945_UCODE_API_MAX,
	.ucode_api_min = IL3945_UCODE_API_MIN,
S
Stanislaw Gruszka 已提交
2732
	.sku = IL_SKU_A|IL_SKU_G,
2733
	.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
S
Stanislaw Gruszka 已提交
2734 2735 2736 2737
	.ops = &il3945_ops,
	.mod_params = &il3945_mod_params,
	.base_params = &il3945_base_params,
	.led_mode = IL_LED_BLINK,
T
Tomas Winkler 已提交
2738 2739
};

S
Stanislaw Gruszka 已提交
2740 2741 2742 2743 2744 2745 2746
DEFINE_PCI_DEVICE_TABLE(il3945_hw_card_ids) = {
	{IL_PCI_DEVICE(0x4222, 0x1005, il3945_bg_cfg)},
	{IL_PCI_DEVICE(0x4222, 0x1034, il3945_bg_cfg)},
	{IL_PCI_DEVICE(0x4222, 0x1044, il3945_bg_cfg)},
	{IL_PCI_DEVICE(0x4227, 0x1014, il3945_bg_cfg)},
	{IL_PCI_DEVICE(0x4222, PCI_ANY_ID, il3945_abg_cfg)},
	{IL_PCI_DEVICE(0x4227, PCI_ANY_ID, il3945_abg_cfg)},
Z
Zhu Yi 已提交
2747 2748 2749
	{0}
};

S
Stanislaw Gruszka 已提交
2750
MODULE_DEVICE_TABLE(pci, il3945_hw_card_ids);