3945.c 75.9 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

W
Winkler, Tomas 已提交
42
#include "iwl-fh.h"
43
#include "iwl-commands.h"
44
#include "iwl-sta.h"
45
#include "iwl-eeprom.h"
K
Kolekar, Abhijeet 已提交
46
#include "iwl-core.h"
47
#include "iwl-helpers.h"
J
Johannes Berg 已提交
48
#include "iwl-led.h"
49
#include "3945.h"
Z
Zhu Yi 已提交
50

51 52 53 54 55
/* Send led command */
static int il3945_send_led_cmd(struct il_priv *il,
				struct il_led_cmd *led_cmd)
{
	struct il_host_cmd cmd = {
56
		.id = C_LEDS,
57 58 59 60 61 62 63 64 65 66 67 68 69
		.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 已提交
70
#define IL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
S
Stanislaw Gruszka 已提交
71
	[RATE_##r##M_IDX] = { RATE_##r##M_PLCP,   \
S
Stanislaw Gruszka 已提交
72
				    RATE_##r##M_IEEE,   \
S
Stanislaw Gruszka 已提交
73 74 75 76 77 78
				    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 已提交
79 80
				    RATE_##r##M_IDX_TBL, \
				    RATE_##ip##M_IDX_TBL }
Z
Zhu Yi 已提交
81 82 83 84 85 86

/*
 * 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 已提交
87
 * maps to RATE_INVALID
Z
Zhu Yi 已提交
88 89
 *
 */
S
Stanislaw Gruszka 已提交
90
const struct il3945_rate_info il3945_rates[RATE_COUNT_3945] = {
S
Stanislaw Gruszka 已提交
91 92 93 94 95 96 97 98 99 100 101 102
	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 已提交
103 104
};

S
Stanislaw Gruszka 已提交
105
static inline u8 il3945_get_prev_ieee_rate(u8 rate_idx)
106
{
S
Stanislaw Gruszka 已提交
107
	u8 rate = il3945_rates[rate_idx].prev_ieee;
108

S
Stanislaw Gruszka 已提交
109
	if (rate == RATE_INVALID)
S
Stanislaw Gruszka 已提交
110
		rate = rate_idx;
111 112 113
	return rate;
}

S
Stanislaw Gruszka 已提交
114 115 116
/* 1 = enable the il3945_disable_events() function */
#define IL_EVT_DISABLE (0)
#define IL_EVT_DISABLE_SIZE (1532/32)
Z
Zhu Yi 已提交
117 118

/**
S
Stanislaw Gruszka 已提交
119
 * il3945_disable_events - Disable selected events in uCode event log
Z
Zhu Yi 已提交
120 121 122 123 124 125
 *
 * 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 已提交
126
 *   ... and set IL_EVT_DISABLE to 1. */
S
Stanislaw Gruszka 已提交
127
void il3945_disable_events(struct il_priv *il)
Z
Zhu Yi 已提交
128 129 130 131 132
{
	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 已提交
133
	static const u32 evt_disable[IL_EVT_DISABLE_SIZE] = {
Z
Zhu Yi 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
		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 已提交
183
	base = le32_to_cpu(il->card_alive.log_event_table_ptr);
S
Stanislaw Gruszka 已提交
184
	if (!il3945_hw_valid_rtc_data_addr(base)) {
185
		IL_ERR("Invalid event log pointer 0x%08X\n", base);
Z
Zhu Yi 已提交
186 187 188
		return;
	}

S
Stanislaw Gruszka 已提交
189 190
	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 已提交
191

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

	} else {
201 202 203
		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 已提交
204 205 206 207 208
			       disable_ptr, array_size);
	}

}

S
Stanislaw Gruszka 已提交
209
static int il3945_hwrate_to_plcp_idx(u8 plcp)
210 211 212
{
	int idx;

S
Stanislaw Gruszka 已提交
213
	for (idx = 0; idx < RATE_COUNT_3945; idx++)
S
Stanislaw Gruszka 已提交
214
		if (il3945_rates[idx].plcp == plcp)
215 216 217 218
			return idx;
	return -1;
}

219
#ifdef CONFIG_IWLEGACY_DEBUG
220
#define TX_STATUS_ENTRY(x) case TX_3945_STATUS_FAIL_ ## x: return #x
221

S
Stanislaw Gruszka 已提交
222
static const char *il3945_get_tx_fail_reason(u32 status)
223 224
{
	switch (status & TX_STATUS_MSK) {
225
	case TX_3945_STATUS_SUCCESS:
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
		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 已提交
248
static inline const char *il3945_get_tx_fail_reason(u32 status)
249 250 251 252 253
{
	return "";
}
#endif

254 255 256 257 258
/*
 * get ieee prev rate from rate scale table.
 * for A and B mode we need to overright prev
 * value
 */
S
Stanislaw Gruszka 已提交
259
int il3945_rs_next_rate(struct il_priv *il, int rate)
260
{
S
Stanislaw Gruszka 已提交
261
	int next_rate = il3945_get_prev_ieee_rate(rate);
262

S
Stanislaw Gruszka 已提交
263
	switch (il->band) {
264
	case IEEE80211_BAND_5GHZ:
S
Stanislaw Gruszka 已提交
265 266 267 268
		if (rate == RATE_12M_IDX)
			next_rate = RATE_9M_IDX;
		else if (rate == RATE_6M_IDX)
			next_rate = RATE_6M_IDX;
269
		break;
270
	case IEEE80211_BAND_2GHZ:
S
Stanislaw Gruszka 已提交
271
		if (!(il->_3945.sta_supp_rates & IL_OFDM_RATES_MASK) &&
272
		    il_is_associated(il)) {
S
Stanislaw Gruszka 已提交
273 274
			if (rate == RATE_11M_IDX)
				next_rate = RATE_5M_IDX;
275
		}
276
		break;
277

278 279 280 281 282 283 284
	default:
		break;
	}

	return next_rate;
}

285 286

/**
S
Stanislaw Gruszka 已提交
287
 * il3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
288
 *
S
Stanislaw Gruszka 已提交
289
 * When FW advances 'R' idx, all entries between old and new 'R' idx
290 291 292
 * 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 已提交
293
static void il3945_tx_queue_reclaim(struct il_priv *il,
S
Stanislaw Gruszka 已提交
294
				     int txq_id, int idx)
295
{
S
Stanislaw Gruszka 已提交
296
	struct il_tx_queue *txq = &il->txq[txq_id];
S
Stanislaw Gruszka 已提交
297 298
	struct il_queue *q = &txq->q;
	struct il_tx_info *tx_info;
299

300
	BUG_ON(txq_id == IL39_CMD_QUEUE_NUM);
301

S
Stanislaw Gruszka 已提交
302 303
	for (idx = il_queue_inc_wrap(idx, q->n_bd);
		q->read_ptr != idx;
S
Stanislaw Gruszka 已提交
304
		q->read_ptr = il_queue_inc_wrap(q->read_ptr, q->n_bd)) {
305 306

		tx_info = &txq->txb[txq->q.read_ptr];
S
Stanislaw Gruszka 已提交
307
		ieee80211_tx_status_irqsafe(il->hw, tx_info->skb);
308
		tx_info->skb = NULL;
S
Stanislaw Gruszka 已提交
309
		il->cfg->ops->lib->txq_free_tfd(il, txq);
310 311
	}

312
	if (il_queue_space(q) > q->low_mark && txq_id >= 0 &&
313
	    txq_id != IL39_CMD_QUEUE_NUM && il->mac80211_registered)
S
Stanislaw Gruszka 已提交
314
		il_wake_queue(il, txq);
315 316 317
}

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

S
Stanislaw Gruszka 已提交
334 335
	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 "
336
			  "is out of range [0-%d] %d %d\n", txq_id,
S
Stanislaw Gruszka 已提交
337
			  idx, txq->q.n_bd, txq->q.write_ptr,
338 339 340 341
			  txq->q.read_ptr);
		return;
	}

342
	txq->time_stamp = jiffies;
343
	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
344 345 346
	ieee80211_tx_info_clear_status(info);

	/* Fill the MRR chain with some info about on-chip retransmissions */
S
Stanislaw Gruszka 已提交
347
	rate_idx = il3945_hwrate_to_plcp_idx(tx_resp->rate);
348
	if (info->band == IEEE80211_BAND_5GHZ)
S
Stanislaw Gruszka 已提交
349
		rate_idx -= IL_FIRST_OFDM_RATE;
350 351

	fail = tx_resp->failure_frame;
352 353 354

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

	/* tx_status->rts_retry_count = tx_resp->failure_rts; */
357 358
	info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
				IEEE80211_TX_STAT_ACK : 0;
359

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

S
Stanislaw Gruszka 已提交
364 365
	D_TX_REPLY("Tx queue reclaim %d\n", idx);
	il3945_tx_queue_reclaim(il, txq_id, idx);
366

J
Johannes Berg 已提交
367
	if (status & TX_ABORT_REQUIRED_MSK)
368
		IL_ERR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
369 370 371 372
}



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

S
Stanislaw Gruszka 已提交
389 390 391
	prev_stats = (__le32 *)&il->_3945.stats;
	accum_stats = (u32 *)&il->_3945.accum_stats;
	delta = (u32 *)&il->_3945.delta_stats;
S
Stanislaw Gruszka 已提交
392
	max_delta = (u32 *)&il->_3945.max_delta;
A
Abhijeet Kolekar 已提交
393

S
Stanislaw Gruszka 已提交
394
	for (i = sizeof(__le32); i < sizeof(struct il3945_notif_stats);
A
Abhijeet Kolekar 已提交
395 396 397 398 399 400 401 402 403 404 405
	     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 已提交
406 407 408 409 410
	/* 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 已提交
411 412
}
#endif
Z
Zhu Yi 已提交
413

S
Stanislaw Gruszka 已提交
414
void il3945_hw_rx_stats(struct il_priv *il,
415
		struct il_rx_buf *rxb)
Z
Zhu Yi 已提交
416
{
417
	struct il_rx_pkt *pkt = rxb_addr(rxb);
A
Abhijeet Kolekar 已提交
418

419
	D_RX("Statistics notification received (%d vs %d).\n",
S
Stanislaw Gruszka 已提交
420
		     (int)sizeof(struct il3945_notif_stats),
421
		     le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
422
#ifdef CONFIG_IWLEGACY_DEBUGFS
S
Stanislaw Gruszka 已提交
423
	il3945_accumulative_stats(il, (__le32 *)&pkt->u.raw);
A
Abhijeet Kolekar 已提交
424
#endif
Z
Zhu Yi 已提交
425

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

S
Stanislaw Gruszka 已提交
429
void il3945_reply_stats(struct il_priv *il,
430
			      struct il_rx_buf *rxb)
A
Abhijeet Kolekar 已提交
431
{
432
	struct il_rx_pkt *pkt = rxb_addr(rxb);
A
Abhijeet Kolekar 已提交
433 434
	__le32 *flag = (__le32 *)&pkt->u.raw;

S
Stanislaw Gruszka 已提交
435
	if (le32_to_cpu(*flag) & UCODE_STATS_CLEAR_MSK) {
436
#ifdef CONFIG_IWLEGACY_DEBUGFS
S
Stanislaw Gruszka 已提交
437 438 439 440
		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 已提交
441
		memset(&il->_3945.max_delta, 0,
S
Stanislaw Gruszka 已提交
442
			sizeof(struct il3945_notif_stats));
A
Abhijeet Kolekar 已提交
443
#endif
444
		D_RX("Statistics have been cleared\n");
A
Abhijeet Kolekar 已提交
445
	}
S
Stanislaw Gruszka 已提交
446
	il3945_hw_rx_stats(il, rxb);
A
Abhijeet Kolekar 已提交
447 448 449
}


450 451 452 453 454 455
/******************************************************************************
 *
 * Misc. internal state and helper functions
 *
 ******************************************************************************/

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

S
Stanislaw Gruszka 已提交
474
static void il3945_pass_packet_to_mac80211(struct il_priv *il,
475
				   struct il_rx_buf *rxb,
Z
Zhu Yi 已提交
476
				   struct ieee80211_rx_status *stats)
Z
Zhu Yi 已提交
477
{
478
	struct il_rx_pkt *pkt = rxb_addr(rxb);
S
Stanislaw Gruszka 已提交
479 480 481
	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 已提交
482 483
	u16 len = le16_to_cpu(rx_hdr->len);
	struct sk_buff *skb;
484
	__le16 fc = hdr->frame_control;
Z
Zhu Yi 已提交
485 486

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

	/* We only process data packets if the interface is open */
S
Stanislaw Gruszka 已提交
494
	if (unlikely(!il->is_open)) {
495
		D_DROP(
496
			"Dropping packet while interface is not open.\n");
Z
Zhu Yi 已提交
497 498 499
		return;
	}

500
	skb = dev_alloc_skb(128);
Z
Zhu Yi 已提交
501
	if (!skb) {
502
		IL_ERR("dev_alloc_skb failed\n");
Z
Zhu Yi 已提交
503 504
		return;
	}
Z
Zhu Yi 已提交
505

S
Stanislaw Gruszka 已提交
506
	if (!il3945_mod_params.sw_crypto)
S
Stanislaw Gruszka 已提交
507
		il_set_decrypted_flag(il,
Z
Zhu Yi 已提交
508
				       (struct ieee80211_hdr *)rxb_addr(rxb),
Z
Zhu Yi 已提交
509 510
				       le32_to_cpu(rx_end->status), stats);

Z
Zhu Yi 已提交
511 512 513
	skb_add_rx_frag(skb, 0, rxb->page,
			(void *)rx_hdr->payload - (void *)pkt, len);

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

S
Stanislaw Gruszka 已提交
517 518
	ieee80211_rx(il->hw, skb);
	il->alloc_rxb_page--;
Z
Zhu Yi 已提交
519
	rxb->page = NULL;
Z
Zhu Yi 已提交
520 521
}

S
Stanislaw Gruszka 已提交
522
#define IL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
523

S
Stanislaw Gruszka 已提交
524
static void il3945_hdl_rx(struct il_priv *il,
525
				struct il_rx_buf *rxb)
Z
Zhu Yi 已提交
526
{
527 528
	struct ieee80211_hdr *header;
	struct ieee80211_rx_status rx_status;
529
	struct il_rx_pkt *pkt = rxb_addr(rxb);
S
Stanislaw Gruszka 已提交
530 531 532
	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);
533 534
	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 已提交
535
	u8 network_packet;
536 537 538 539 540

	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;
541 542 543
	rx_status.freq =
		ieee80211_channel_to_frequency(le16_to_cpu(rx_hdr->channel),
					       rx_status.band);
544

S
Stanislaw Gruszka 已提交
545
	rx_status.rate_idx = il3945_hwrate_to_plcp_idx(rx_hdr->rate);
546
	if (rx_status.band == IEEE80211_BAND_5GHZ)
S
Stanislaw Gruszka 已提交
547
		rx_status.rate_idx -= IL_FIRST_OFDM_RATE;
Z
Zhu Yi 已提交
548

R
Reinette Chatre 已提交
549
	rx_status.antenna = (le16_to_cpu(rx_hdr->phy_flags) &
550 551 552 553 554 555
					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 已提交
556
	if ((unlikely(rx_stats->phy_count > 20))) {
557
		D_DROP("dsp size out of range [0,20]: %d/n",
558
				rx_stats->phy_count);
Z
Zhu Yi 已提交
559 560 561
		return;
	}

562 563
	if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR) ||
	    !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
564
		D_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status);
Z
Zhu Yi 已提交
565 566 567
		return;
	}

568

Z
Zhu Yi 已提交
569 570

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

573
	D_STATS("Rssi %d sig_avg %d noise_diff %d\n",
J
Johannes Berg 已提交
574 575
			rx_status.signal, rx_stats_sig_avg,
			rx_stats_noise_diff);
Z
Zhu Yi 已提交
576

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

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

581
	D_STATS("[%c] %d RSSI:%d Signal:%u, Rate:%u\n",
582 583
			      network_packet ? '*' : ' ',
			      le16_to_cpu(rx_hdr->channel),
584
			      rx_status.signal, rx_status.signal,
J
Johannes Berg 已提交
585
			      rx_status.rate_idx);
Z
Zhu Yi 已提交
586

S
Stanislaw Gruszka 已提交
587
	il_dbg_log_rx_data_frame(il, le16_to_cpu(rx_hdr->len),
588
						header);
Z
Zhu Yi 已提交
589 590

	if (network_packet) {
S
Stanislaw Gruszka 已提交
591
		il->_3945.last_beacon_time =
592
			le32_to_cpu(rx_end->beacon_timestamp);
S
Stanislaw Gruszka 已提交
593 594
		il->_3945.last_tsf = le64_to_cpu(rx_end->timestamp);
		il->_3945.last_rx_rssi = rx_status.signal;
Z
Zhu Yi 已提交
595 596
	}

S
Stanislaw Gruszka 已提交
597
	il3945_pass_packet_to_mac80211(il, rxb, &rx_status);
Z
Zhu Yi 已提交
598 599
}

S
Stanislaw Gruszka 已提交
600
int il3945_hw_txq_attach_buf_to_tfd(struct il_priv *il,
S
Stanislaw Gruszka 已提交
601
				     struct il_tx_queue *txq,
602
				     dma_addr_t addr, u16 len, u8 reset, u8 pad)
Z
Zhu Yi 已提交
603 604
{
	int count;
S
Stanislaw Gruszka 已提交
605 606
	struct il_queue *q;
	struct il3945_tfd *tfd, *tfd_tmp;
607 608

	q = &txq->q;
S
Stanislaw Gruszka 已提交
609
	tfd_tmp = (struct il3945_tfd *)txq->tfds;
610
	tfd = &tfd_tmp[q->write_ptr];
611 612 613

	if (reset)
		memset(tfd, 0, sizeof(*tfd));
Z
Zhu Yi 已提交
614 615 616

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

617
	if (count >= NUM_TFD_CHUNKS || count < 0) {
618
		IL_ERR("Error can not send more than %d chunks\n",
Z
Zhu Yi 已提交
619 620 621 622
			  NUM_TFD_CHUNKS);
		return -EINVAL;
	}

W
Winkler, Tomas 已提交
623 624
	tfd->tbs[count].addr = cpu_to_le32(addr);
	tfd->tbs[count].len = cpu_to_le32(len);
Z
Zhu Yi 已提交
625 626 627 628 629 630 631 632 633 634

	count++;

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

	return 0;
}

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

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

656 657 658
	/* Unmap tx_cmd */
	if (counter)
		pci_unmap_single(dev,
S
Stanislaw Gruszka 已提交
659 660
				dma_unmap_addr(&txq->meta[idx], mapping),
				dma_unmap_len(&txq->meta[idx], len),
661 662
				PCI_DMA_TODEVICE);

Z
Zhu Yi 已提交
663 664
	/* unmap chunks if any */

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

669 670 671
	/* free SKB */
	if (txq->txb) {
		struct sk_buff *skb;
J
Johannes Berg 已提交
672

673 674 675 676 677 678
		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 已提交
679 680 681 682 683
		}
	}
}

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

S
Stanislaw Gruszka 已提交
703
	rate = il3945_rates[rate_idx].plcp;
A
Abhijeet Kolekar 已提交
704
	tx_flags = tx_cmd->tx_flags;
Z
Zhu Yi 已提交
705 706

	/* We need to figure out how to get the sta->supp_rates while
707
	 * in this running context */
S
Stanislaw Gruszka 已提交
708
	rate_mask = RATES_MASK_3945;
A
Abhijeet Kolekar 已提交
709 710 711 712 713

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

717
	if (tx_id >= IL39_CMD_QUEUE_NUM)
Z
Zhu Yi 已提交
718 719 720 721
		rts_retry_limit = 3;
	else
		rts_retry_limit = 7;

A
Abhijeet Kolekar 已提交
722 723 724
	if (data_retry_limit < rts_retry_limit)
		rts_retry_limit = data_retry_limit;
	tx_cmd->rts_retry_limit = rts_retry_limit;
Z
Zhu Yi 已提交
725

A
Abhijeet Kolekar 已提交
726 727
	tx_cmd->rate = rate;
	tx_cmd->tx_flags = tx_flags;
Z
Zhu Yi 已提交
728 729

	/* OFDM */
A
Abhijeet Kolekar 已提交
730
	tx_cmd->supp_rates[0] =
S
Stanislaw Gruszka 已提交
731
	   ((rate_mask & IL_OFDM_RATES_MASK) >> IL_FIRST_OFDM_RATE) & 0xFF;
Z
Zhu Yi 已提交
732 733

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

736
	D_RATE("Tx sta id: %d, rate: %d (plcp), flags: 0x%4X "
Z
Zhu Yi 已提交
737
		       "cck/ofdm mask: 0x%x/0x%x\n", sta_id,
A
Abhijeet Kolekar 已提交
738 739
		       tx_cmd->rate, le32_to_cpu(tx_cmd->tx_flags),
		       tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
Z
Zhu Yi 已提交
740 741
}

S
Stanislaw Gruszka 已提交
742
static u8 il3945_sync_sta(struct il_priv *il, int sta_id, u16 tx_rate)
Z
Zhu Yi 已提交
743 744
{
	unsigned long flags_spin;
S
Stanislaw Gruszka 已提交
745
	struct il_station_entry *station;
Z
Zhu Yi 已提交
746

S
Stanislaw Gruszka 已提交
747 748
	if (sta_id == IL_INVALID_STATION)
		return IL_INVALID_STATION;
Z
Zhu Yi 已提交
749

S
Stanislaw Gruszka 已提交
750 751
	spin_lock_irqsave(&il->sta_lock, flags_spin);
	station = &il->stations[sta_id];
Z
Zhu Yi 已提交
752 753 754 755

	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 已提交
756 757
	il_send_add_sta(il, &station->sta, CMD_ASYNC);
	spin_unlock_irqrestore(&il->sta_lock, flags_spin);
Z
Zhu Yi 已提交
758

759
	D_RATE("SCALE sync station %d to rate %d\n",
Z
Zhu Yi 已提交
760 761 762 763
			sta_id, tx_rate);
	return sta_id;
}

S
Stanislaw Gruszka 已提交
764
static void il3945_set_pwr_vmain(struct il_priv *il)
Z
Zhu Yi 已提交
765
{
766 767 768 769
/*
 * (for documentation purposes)
 * to set power to V_AUX, do

S
Stanislaw Gruszka 已提交
770 771
		if (pci_pme_capable(il->pci_dev, PCI_D3cold)) {
			il_set_bits_mask_prph(il, APMG_PS_CTRL_REG,
Z
Zhu Yi 已提交
772 773 774
					APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
					~APMG_PS_CTRL_MSK_PWR_SRC);

775
			_il_poll_bit(il, CSR_GPIO_IN,
Z
Zhu Yi 已提交
776 777
				     CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
				     CSR_GPIO_IN_BIT_AUX_POWER, 5000);
778
		}
779
 */
Z
Zhu Yi 已提交
780

S
Stanislaw Gruszka 已提交
781
	il_set_bits_mask_prph(il, APMG_PS_CTRL_REG,
782 783
			APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
			~APMG_PS_CTRL_MSK_PWR_SRC);
Z
Zhu Yi 已提交
784

785
	_il_poll_bit(il, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
786
		     CSR_GPIO_IN_BIT_AUX_POWER, 5000);	/* uS */
Z
Zhu Yi 已提交
787 788
}

S
Stanislaw Gruszka 已提交
789
static int il3945_rx_init(struct il_priv *il, struct il_rx_queue *rxq)
Z
Zhu Yi 已提交
790
{
791 792
	il_wr(il, FH39_RCSR_RBD_BASE(0), rxq->bd_dma);
	il_wr(il, FH39_RCSR_RPTR_ADDR(0),
793
					rxq->rb_stts_dma);
794 795
	il_wr(il, FH39_RCSR_WPTR(0), 0);
	il_wr(il, FH39_RCSR_CONFIG(0),
796 797 798 799 800 801 802 803
		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 已提交
804 805

	/* fake read to flush all prev I/O */
806
	il_rd(il, FH39_RSSR_CTRL);
Z
Zhu Yi 已提交
807 808 809 810

	return 0;
}

S
Stanislaw Gruszka 已提交
811
static int il3945_tx_reset(struct il_priv *il)
Z
Zhu Yi 已提交
812 813 814
{

	/* bypass mode */
815
	il_wr_prph(il, ALM_SCD_MODE_REG, 0x2);
Z
Zhu Yi 已提交
816 817

	/* RA 0 is active */
818
	il_wr_prph(il, ALM_SCD_ARASTAT_REG, 0x01);
Z
Zhu Yi 已提交
819 820

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

823 824 825 826
	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 已提交
827

828
	il_wr(il, FH39_TSSR_CBB_BASE,
S
Stanislaw Gruszka 已提交
829
			     il->_3945.shared_phys);
Z
Zhu Yi 已提交
830

831
	il_wr(il, FH39_TSSR_MSG_CONFIG,
832 833 834 835 836 837 838
		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 已提交
839 840 841 842 843 844


	return 0;
}

/**
S
Stanislaw Gruszka 已提交
845
 * il3945_txq_ctx_reset - Reset TX queue context
Z
Zhu Yi 已提交
846 847 848
 *
 * Destroys all DMA structures and initialize them again
 */
S
Stanislaw Gruszka 已提交
849
static int il3945_txq_ctx_reset(struct il_priv *il)
Z
Zhu Yi 已提交
850 851 852 853
{
	int rc;
	int txq_id, slots_num;

S
Stanislaw Gruszka 已提交
854
	il3945_hw_txq_ctx_free(il);
Z
Zhu Yi 已提交
855

856
	/* allocate tx queue structure */
S
Stanislaw Gruszka 已提交
857
	rc = il_alloc_txq_mem(il);
858 859 860
	if (rc)
		return rc;

Z
Zhu Yi 已提交
861
	/* Tx CMD queue */
S
Stanislaw Gruszka 已提交
862
	rc = il3945_tx_reset(il);
Z
Zhu Yi 已提交
863 864 865 866
	if (rc)
		goto error;

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

	return rc;

 error:
S
Stanislaw Gruszka 已提交
881
	il3945_hw_txq_ctx_free(il);
Z
Zhu Yi 已提交
882 883 884
	return rc;
}

885

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

B
Ben Cahill 已提交
895
	/* Clear APMG (NIC's internal power management) interrupts */
896 897
	il_wr_prph(il, APMG_RTC_INT_MSK_REG, 0x0);
	il_wr_prph(il, APMG_RTC_INT_STT_REG, 0xFFFFFFFF);
B
Ben Cahill 已提交
898 899

	/* Reset radio chip */
S
Stanislaw Gruszka 已提交
900
	il_set_bits_prph(il, APMG_PS_CTRL_REG,
901
				APMG_PS_CTRL_VAL_RESET_REQ);
B
Ben Cahill 已提交
902
	udelay(5);
S
Stanislaw Gruszka 已提交
903
	il_clear_bits_prph(il, APMG_PS_CTRL_REG,
904
				APMG_PS_CTRL_VAL_RESET_REQ);
B
Ben Cahill 已提交
905

K
Kolekar, Abhijeet 已提交
906 907
	return ret;
}
Z
Zhu Yi 已提交
908

S
Stanislaw Gruszka 已提交
909
static void il3945_nic_config(struct il_priv *il)
K
Kolekar, Abhijeet 已提交
910
{
S
Stanislaw Gruszka 已提交
911
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
K
Kolekar, Abhijeet 已提交
912
	unsigned long flags;
S
Stanislaw Gruszka 已提交
913
	u8 rev_id = il->pci_dev->revision;
Z
Zhu Yi 已提交
914

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

917
	/* Determine HW type */
918
	D_INFO("HW Revision ID = 0x%X\n", rev_id);
919

Z
Zhu Yi 已提交
920
	if (rev_id & PCI_CFG_REV_ID_BIT_RTP)
921
		D_INFO("RTP type\n");
Z
Zhu Yi 已提交
922
	else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
923
		D_INFO("3945 RADIO-MB type\n");
S
Stanislaw Gruszka 已提交
924
		il_set_bit(il, CSR_HW_IF_CONFIG_REG,
T
Tomas Winkler 已提交
925
			    CSR39_HW_IF_CONFIG_REG_BIT_3945_MB);
Z
Zhu Yi 已提交
926
	} else {
927
		D_INFO("3945 RADIO-MM type\n");
S
Stanislaw Gruszka 已提交
928
		il_set_bit(il, CSR_HW_IF_CONFIG_REG,
T
Tomas Winkler 已提交
929
			    CSR39_HW_IF_CONFIG_REG_BIT_3945_MM);
Z
Zhu Yi 已提交
930 931
	}

932
	if (EEPROM_SKU_CAP_OP_MODE_MRC == eeprom->sku_cap) {
933
		D_INFO("SKU OP mode is mrc\n");
S
Stanislaw Gruszka 已提交
934
		il_set_bit(il, CSR_HW_IF_CONFIG_REG,
T
Tomas Winkler 已提交
935
			    CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC);
Z
Zhu Yi 已提交
936
	} else
937
		D_INFO("SKU OP mode is basic\n");
Z
Zhu Yi 已提交
938

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

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

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

967
	if (eeprom->sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
968
		D_RF_KILL("HW RF KILL supported in EEPROM.\n");
K
Kolekar, Abhijeet 已提交
969 970
}

S
Stanislaw Gruszka 已提交
971
int il3945_hw_nic_init(struct il_priv *il)
K
Kolekar, Abhijeet 已提交
972 973 974
{
	int rc;
	unsigned long flags;
S
Stanislaw Gruszka 已提交
975
	struct il_rx_queue *rxq = &il->rxq;
K
Kolekar, Abhijeet 已提交
976

S
Stanislaw Gruszka 已提交
977 978 979
	spin_lock_irqsave(&il->lock, flags);
	il->cfg->ops->lib->apm_ops.init(il);
	spin_unlock_irqrestore(&il->lock, flags);
K
Kolekar, Abhijeet 已提交
980

S
Stanislaw Gruszka 已提交
981
	il3945_set_pwr_vmain(il);
K
Kolekar, Abhijeet 已提交
982

S
Stanislaw Gruszka 已提交
983
	il->cfg->ops->lib->apm_ops.config(il);
Z
Zhu Yi 已提交
984 985 986

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

S
Stanislaw Gruszka 已提交
995
	il3945_rx_replenish(il);
Z
Zhu Yi 已提交
996

S
Stanislaw Gruszka 已提交
997
	il3945_rx_init(il, rxq);
Z
Zhu Yi 已提交
998 999 1000 1001


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

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

S
Stanislaw Gruszka 已提交
1007
	rc = il3945_txq_ctx_reset(il);
Z
Zhu Yi 已提交
1008 1009 1010
	if (rc)
		return rc;

S
Stanislaw Gruszka 已提交
1011
	set_bit(S_INIT, &il->status);
Z
Zhu Yi 已提交
1012 1013 1014 1015 1016

	return 0;
}

/**
S
Stanislaw Gruszka 已提交
1017
 * il3945_hw_txq_ctx_free - Free TXQ Context
Z
Zhu Yi 已提交
1018 1019 1020
 *
 * Destroy all TX DMA queues and structures
 */
S
Stanislaw Gruszka 已提交
1021
void il3945_hw_txq_ctx_free(struct il_priv *il)
Z
Zhu Yi 已提交
1022 1023 1024 1025
{
	int txq_id;

	/* Tx queues */
S
Stanislaw Gruszka 已提交
1026 1027
	if (il->txq)
		for (txq_id = 0; txq_id < il->hw_params.max_txq_num;
1028
		     txq_id++)
1029
			if (txq_id == IL39_CMD_QUEUE_NUM)
S
Stanislaw Gruszka 已提交
1030
				il_cmd_queue_free(il);
1031
			else
S
Stanislaw Gruszka 已提交
1032
				il_tx_queue_free(il, txq_id);
1033

1034
	/* free tx queue structure */
S
Stanislaw Gruszka 已提交
1035
	il_txq_mem(il);
Z
Zhu Yi 已提交
1036 1037
}

S
Stanislaw Gruszka 已提交
1038
void il3945_hw_txq_ctx_stop(struct il_priv *il)
Z
Zhu Yi 已提交
1039
{
1040
	int txq_id;
Z
Zhu Yi 已提交
1041 1042

	/* stop SCD */
1043 1044
	il_wr_prph(il, ALM_SCD_MODE_REG, 0);
	il_wr_prph(il, ALM_SCD_TXFACT_REG, 0);
Z
Zhu Yi 已提交
1045 1046

	/* reset TFD queues */
S
Stanislaw Gruszka 已提交
1047
	for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++) {
1048 1049
		il_wr(il, FH39_TCSR_CONFIG(txq_id), 0x0);
		il_poll_bit(il, FH39_TSSR_TX_STATUS,
1050
				FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
Z
Zhu Yi 已提交
1051 1052 1053
				1000);
	}

S
Stanislaw Gruszka 已提交
1054
	il3945_hw_txq_ctx_free(il);
Z
Zhu Yi 已提交
1055 1056 1057
}

/**
S
Stanislaw Gruszka 已提交
1058
 * il3945_hw_reg_adjust_power_by_temp
S
Stanislaw Gruszka 已提交
1059
 * return idx delta into power gain settings table
1060
*/
S
Stanislaw Gruszka 已提交
1061
static int il3945_hw_reg_adjust_power_by_temp(int new_reading, int old_reading)
Z
Zhu Yi 已提交
1062 1063 1064 1065 1066
{
	return (new_reading - old_reading) * (-11) / 100;
}

/**
S
Stanislaw Gruszka 已提交
1067
 * il3945_hw_reg_temp_out_of_range - Keep temperature in sane range
Z
Zhu Yi 已提交
1068
 */
S
Stanislaw Gruszka 已提交
1069
static inline int il3945_hw_reg_temp_out_of_range(int temperature)
Z
Zhu Yi 已提交
1070
{
1071
	return (temperature < -260 || temperature > 25) ? 1 : 0;
Z
Zhu Yi 已提交
1072 1073
}

S
Stanislaw Gruszka 已提交
1074
int il3945_hw_get_temperature(struct il_priv *il)
Z
Zhu Yi 已提交
1075
{
1076
	return _il_rd(il, CSR_UCODE_DRV_GP2);
Z
Zhu Yi 已提交
1077 1078 1079
}

/**
S
Stanislaw Gruszka 已提交
1080
 * il3945_hw_reg_txpower_get_temperature
1081 1082
 * get the current temperature by reading from NIC
*/
S
Stanislaw Gruszka 已提交
1083
static int il3945_hw_reg_txpower_get_temperature(struct il_priv *il)
Z
Zhu Yi 已提交
1084
{
S
Stanislaw Gruszka 已提交
1085
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
Z
Zhu Yi 已提交
1086 1087
	int temperature;

S
Stanislaw Gruszka 已提交
1088
	temperature = il3945_hw_get_temperature(il);
Z
Zhu Yi 已提交
1089 1090 1091

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

	/* handle insane temp reading */
S
Stanislaw Gruszka 已提交
1095
	if (il3945_hw_reg_temp_out_of_range(temperature)) {
1096
		IL_ERR("Error bad temperature value  %d\n", temperature);
Z
Zhu Yi 已提交
1097 1098 1099

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

	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 已提交
1112
#define IL_TEMPERATURE_LIMIT_TIMER   6
Z
Zhu Yi 已提交
1113 1114

/**
S
Stanislaw Gruszka 已提交
1115
 * il3945_is_temp_calib_needed - determines if new calibration is needed
Z
Zhu Yi 已提交
1116 1117 1118 1119
 *
 * 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 已提交
1120
static int il3945_is_temp_calib_needed(struct il_priv *il)
Z
Zhu Yi 已提交
1121 1122 1123
{
	int temp_diff;

S
Stanislaw Gruszka 已提交
1124 1125
	il->temperature = il3945_hw_reg_txpower_get_temperature(il);
	temp_diff = il->temperature - il->last_temperature;
Z
Zhu Yi 已提交
1126 1127 1128

	/* get absolute value */
	if (temp_diff < 0) {
1129
		D_POWER("Getting cooler, delta %d,\n", temp_diff);
Z
Zhu Yi 已提交
1130 1131
		temp_diff = -temp_diff;
	} else if (temp_diff == 0)
1132
		D_POWER("Same temp,\n");
Z
Zhu Yi 已提交
1133
	else
1134
		D_POWER("Getting warmer, delta %d,\n", temp_diff);
Z
Zhu Yi 已提交
1135 1136

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

1142
	D_POWER("Timed thermal calib needed\n");
Z
Zhu Yi 已提交
1143 1144 1145

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

S
Stanislaw Gruszka 已提交
1150 1151
#define IL_MAX_GAIN_ENTRIES 78
#define IL_CCK_FROM_OFDM_POWER_DIFF  -5
S
Stanislaw Gruszka 已提交
1152
#define IL_CCK_FROM_OFDM_IDX_DIFF (10)
Z
Zhu Yi 已提交
1153 1154 1155

/* 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 已提交
1156
static struct il3945_tx_power power_gain_table[2][IL_MAX_GAIN_ENTRIES] = {
Z
Zhu Yi 已提交
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 1311 1312 1313 1314 1315 1316
	{
	 {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 已提交
1317
static inline u8 il3945_hw_reg_fix_power_idx(int idx)
Z
Zhu Yi 已提交
1318
{
S
Stanislaw Gruszka 已提交
1319
	if (idx < 0)
Z
Zhu Yi 已提交
1320
		return 0;
S
Stanislaw Gruszka 已提交
1321
	if (idx >= IL_MAX_GAIN_ENTRIES)
S
Stanislaw Gruszka 已提交
1322
		return IL_MAX_GAIN_ENTRIES - 1;
S
Stanislaw Gruszka 已提交
1323
	return (u8) idx;
Z
Zhu Yi 已提交
1324 1325 1326 1327 1328 1329
}

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

/**
S
Stanislaw Gruszka 已提交
1330
 * il3945_hw_reg_set_scan_power - Set Tx power for scan probe requests
Z
Zhu Yi 已提交
1331 1332 1333 1334
 *
 * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK)
 * or 6 Mbit (OFDM) rates.
 */
S
Stanislaw Gruszka 已提交
1335 1336
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 已提交
1337
			       struct il_channel_info *ch_info,
S
Stanislaw Gruszka 已提交
1338
			       int band_idx)
Z
Zhu Yi 已提交
1339
{
S
Stanislaw Gruszka 已提交
1340
	struct il3945_scan_power_info *scan_power_info;
Z
Zhu Yi 已提交
1341
	s8 power;
S
Stanislaw Gruszka 已提交
1342
	u8 power_idx;
Z
Zhu Yi 已提交
1343

S
Stanislaw Gruszka 已提交
1344
	scan_power_info = &ch_info->scan_pwr_info[scan_tbl_idx];
Z
Zhu Yi 已提交
1345 1346 1347 1348

	/* 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 已提交
1349
	power = min(ch_info->scan_power, clip_pwrs[RATE_6M_IDX_TBL]);
Z
Zhu Yi 已提交
1350

S
Stanislaw Gruszka 已提交
1351
	power = min(power, il->tx_power_user_lmt);
Z
Zhu Yi 已提交
1352 1353 1354 1355
	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 已提交
1356
	 *   current "normal" temperature-compensated Tx power *idx* for
Z
Zhu Yi 已提交
1357
	 *   this rate (1Mb or 6Mb) to yield new temp-compensated scan power
S
Stanislaw Gruszka 已提交
1358 1359
	 *   *idx*. */
	power_idx = ch_info->power_info[rate_idx].power_table_idx
Z
Zhu Yi 已提交
1360
	    - (power - ch_info->power_info
S
Stanislaw Gruszka 已提交
1361
	       [RATE_6M_IDX_TBL].requested_power) * 2;
Z
Zhu Yi 已提交
1362

S
Stanislaw Gruszka 已提交
1363
	/* store reference idx that we use when adjusting *all* scan
Z
Zhu Yi 已提交
1364 1365 1366
	 *   powers.  So we can accommodate user (all channel) or spectrum
	 *   management (single channel) power changes "between" temperature
	 *   feedback compensation procedures.
S
Stanislaw Gruszka 已提交
1367
	 * don't force fit this reference idx into gain table; it may be a
Z
Zhu Yi 已提交
1368 1369 1370 1371 1372
	 *   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 已提交
1373
	power_idx = il3945_hw_reg_fix_power_idx(power_idx);
Z
Zhu Yi 已提交
1374

S
Stanislaw Gruszka 已提交
1375
	scan_power_info->power_table_idx = power_idx;
Z
Zhu Yi 已提交
1376
	scan_power_info->tpc.tx_gain =
S
Stanislaw Gruszka 已提交
1377
	    power_gain_table[band_idx][power_idx].tx_gain;
Z
Zhu Yi 已提交
1378
	scan_power_info->tpc.dsp_atten =
S
Stanislaw Gruszka 已提交
1379
	    power_gain_table[band_idx][power_idx].dsp_atten;
Z
Zhu Yi 已提交
1380 1381 1382
}

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

S
Stanislaw Gruszka 已提交
1397
	if (WARN_ONCE(test_bit(S_SCAN_HW, &il->status),
1398 1399 1400
		      "TX Power requested while scanning!\n"))
		return -EAGAIN;

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

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

S
Stanislaw Gruszka 已提交
1412
	if (!il_is_channel_valid(ch_info)) {
S
Stanislaw Gruszka 已提交
1413
		D_POWER("Not calling TX_PWR_TBL_CMD on "
Z
Zhu Yi 已提交
1414 1415 1416 1417 1418
				"non-Tx channel.\n");
		return 0;
	}

	/* fill cmd with power settings for all rates for current channel */
1419
	/* Fill OFDM rate */
S
Stanislaw Gruszka 已提交
1420
	for (rate_idx = IL_FIRST_OFDM_RATE, i = 0;
1421
	     rate_idx <= IL39_LAST_OFDM_RATE; rate_idx++, i++) {
1422 1423

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

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

1439
		D_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n",
1440 1441 1442 1443 1444
				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 已提交
1445 1446
	}

1447
	return il_send_cmd_pdu(il, C_TX_PWR_TBL,
S
Stanislaw Gruszka 已提交
1448
				sizeof(struct il3945_txpowertable_cmd),
1449
				&txpower);
Z
Zhu Yi 已提交
1450 1451 1452 1453

}

/**
S
Stanislaw Gruszka 已提交
1454
 * il3945_hw_reg_set_new_power - Configures power tables at new levels
Z
Zhu Yi 已提交
1455 1456
 * @ch_info: Channel to update.  Uses power_info.requested_power.
 *
S
Stanislaw Gruszka 已提交
1457
 * Replace requested_power and base_power_idx ch_info fields for
Z
Zhu Yi 已提交
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
 * 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 已提交
1469
static int il3945_hw_reg_set_new_power(struct il_priv *il,
S
Stanislaw Gruszka 已提交
1470
			     struct il_channel_info *ch_info)
Z
Zhu Yi 已提交
1471
{
S
Stanislaw Gruszka 已提交
1472
	struct il3945_channel_power_info *power_info;
Z
Zhu Yi 已提交
1473 1474 1475 1476 1477 1478
	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 已提交
1479
	clip_pwrs = il->_3945.clip_groups[ch_info->group_idx].clip_powers;
Z
Zhu Yi 已提交
1480 1481 1482 1483 1484

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

	/* update OFDM Txpower settings */
S
Stanislaw Gruszka 已提交
1485
	for (i = RATE_6M_IDX_TBL; i <= RATE_54M_IDX_TBL;
Z
Zhu Yi 已提交
1486 1487 1488 1489 1490 1491 1492 1493 1494
	     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 已提交
1495
		 *    update base (non-temp-compensated) power idx */
Z
Zhu Yi 已提交
1496
		delta_idx = (power - power_info->requested_power) * 2;
S
Stanislaw Gruszka 已提交
1497
		power_info->base_power_idx -= delta_idx;
Z
Zhu Yi 已提交
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508

		/* 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 已提交
1509
		    ch_info->power_info[RATE_12M_IDX_TBL].
S
Stanislaw Gruszka 已提交
1510
		    requested_power + IL_CCK_FROM_OFDM_POWER_DIFF;
Z
Zhu Yi 已提交
1511

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

	return 0;
}

/**
S
Stanislaw Gruszka 已提交
1526
 * il3945_hw_reg_get_ch_txpower_limit - returns new power limit for channel
Z
Zhu Yi 已提交
1527 1528 1529 1530 1531
 *
 * 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 已提交
1532
static int il3945_hw_reg_get_ch_txpower_limit(struct il_channel_info *ch_info)
Z
Zhu Yi 已提交
1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550
{
	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 已提交
1551
 * il3945_hw_reg_comp_txpower_temp - Compensate for temperature
Z
Zhu Yi 已提交
1552 1553 1554 1555
 *
 * 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 已提交
1556
 *   on the channel's base_power_idx.
Z
Zhu Yi 已提交
1557 1558 1559
 *
 * If RxOn is "associated", this sends the new Txpower to NIC!
 */
S
Stanislaw Gruszka 已提交
1560
static int il3945_hw_reg_comp_txpower_temp(struct il_priv *il)
Z
Zhu Yi 已提交
1561
{
S
Stanislaw Gruszka 已提交
1562
	struct il_channel_info *ch_info = NULL;
S
Stanislaw Gruszka 已提交
1563
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
S
Stanislaw Gruszka 已提交
1564
	int delta_idx;
Z
Zhu Yi 已提交
1565 1566
	const s8 *clip_pwrs; /* array of h/w max power levels for each rate */
	u8 a_band;
S
Stanislaw Gruszka 已提交
1567 1568
	u8 rate_idx;
	u8 scan_tbl_idx;
Z
Zhu Yi 已提交
1569 1570
	u8 i;
	int ref_temp;
S
Stanislaw Gruszka 已提交
1571
	int temperature = il->temperature;
Z
Zhu Yi 已提交
1572

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

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

S
Stanislaw Gruszka 已提交
1587
		/* get power idx adjustment based on current and factory
Z
Zhu Yi 已提交
1588
		 * temps */
S
Stanislaw Gruszka 已提交
1589
		delta_idx = il3945_hw_reg_adjust_power_by_temp(temperature,
Z
Zhu Yi 已提交
1590 1591 1592
							      ref_temp);

		/* set tx power value for all rates, OFDM and CCK */
S
Stanislaw Gruszka 已提交
1593 1594
		for (rate_idx = 0; rate_idx < RATE_COUNT_3945;
		     rate_idx++) {
Z
Zhu Yi 已提交
1595
			int power_idx =
S
Stanislaw Gruszka 已提交
1596
			    ch_info->power_info[rate_idx].base_power_idx;
Z
Zhu Yi 已提交
1597 1598

			/* temperature compensate */
S
Stanislaw Gruszka 已提交
1599
			power_idx += delta_idx;
Z
Zhu Yi 已提交
1600 1601

			/* stay within table range */
S
Stanislaw Gruszka 已提交
1602 1603 1604 1605
			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 已提交
1606 1607 1608 1609
			    power_gain_table[a_band][power_idx];
		}

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

		/* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */
S
Stanislaw Gruszka 已提交
1613 1614 1615
		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 已提交
1616
			    RATE_1M_IDX_TBL : RATE_6M_IDX_TBL;
S
Stanislaw Gruszka 已提交
1617 1618
			il3945_hw_reg_set_scan_power(il, scan_tbl_idx,
					   actual_idx, clip_pwrs,
Z
Zhu Yi 已提交
1619 1620 1621 1622 1623
					   ch_info, a_band);
		}
	}

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

S
Stanislaw Gruszka 已提交
1627
int il3945_hw_reg_set_txpower(struct il_priv *il, s8 power)
Z
Zhu Yi 已提交
1628
{
S
Stanislaw Gruszka 已提交
1629
	struct il_channel_info *ch_info;
Z
Zhu Yi 已提交
1630 1631 1632 1633
	s8 max_power;
	u8 a_band;
	u8 i;

S
Stanislaw Gruszka 已提交
1634
	if (il->tx_power_user_lmt == power) {
1635
		D_POWER("Requested Tx power same as current "
Z
Zhu Yi 已提交
1636 1637 1638 1639
				"limit: %ddBm.\n", power);
		return 0;
	}

1640
	D_POWER("Setting upper limit clamp to %ddBm.\n", power);
S
Stanislaw Gruszka 已提交
1641
	il->tx_power_user_lmt = power;
Z
Zhu Yi 已提交
1642 1643 1644

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

S
Stanislaw Gruszka 已提交
1645 1646
	for (i = 0; i < il->channel_count; i++) {
		ch_info = &il->channel_info[i];
S
Stanislaw Gruszka 已提交
1647
		a_band = il_is_channel_a_band(ch_info);
Z
Zhu Yi 已提交
1648 1649 1650

		/* find minimum power of all user and regulatory constraints
		 *    (does not consider h/w clipping limitations) */
S
Stanislaw Gruszka 已提交
1651
		max_power = il3945_hw_reg_get_ch_txpower_limit(ch_info);
Z
Zhu Yi 已提交
1652 1653 1654 1655 1656
		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 已提交
1657
			il3945_hw_reg_set_new_power(il, ch_info);
Z
Zhu Yi 已提交
1658 1659 1660 1661 1662
		}
	}

	/* update txpower settings for all channels,
	 *   send to NIC if associated. */
S
Stanislaw Gruszka 已提交
1663 1664
	il3945_is_temp_calib_needed(il);
	il3945_hw_reg_comp_txpower_temp(il);
Z
Zhu Yi 已提交
1665 1666 1667 1668

	return 0;
}

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

1684 1685 1686 1687
	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) {
1688
		D_INFO("Using current RXON_ASSOC.  Not resending.\n");
1689 1690 1691
		return 0;
	}

1692 1693 1694 1695
	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;
1696 1697
	rxon_assoc.reserved = 0;

S
Stanislaw Gruszka 已提交
1698
	rc = il_send_cmd_sync(il, &cmd);
1699 1700 1701
	if (rc)
		return rc;

1702
	pkt = (struct il_rx_pkt *)cmd.reply_page;
S
Stanislaw Gruszka 已提交
1703
	if (pkt->hdr.flags & IL_CMD_FAILED_MSK) {
1704
		IL_ERR("Bad return from C_RXON_ASSOC command\n");
1705 1706 1707
		rc = -EIO;
	}

S
Stanislaw Gruszka 已提交
1708
	il_free_pages(il, cmd.reply_page);
1709 1710 1711 1712

	return rc;
}

A
Abhijeet Kolekar 已提交
1713
/**
S
Stanislaw Gruszka 已提交
1714
 * il3945_commit_rxon - commit staging_rxon to hardware
A
Abhijeet Kolekar 已提交
1715 1716 1717 1718 1719 1720
 *
 * 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 已提交
1721
int il3945_commit_rxon(struct il_priv *il, struct il_rxon_context *ctx)
A
Abhijeet Kolekar 已提交
1722 1723
{
	/* cast away the const for active_rxon in this function */
S
Stanislaw Gruszka 已提交
1724 1725
	struct il3945_rxon_cmd *active_rxon = (void *)&ctx->active;
	struct il3945_rxon_cmd *staging_rxon = (void *)&ctx->staging;
A
Abhijeet Kolekar 已提交
1726
	int rc = 0;
1727
	bool new_assoc = !!(staging_rxon->filter_flags & RXON_FILTER_ASSOC_MSK);
A
Abhijeet Kolekar 已提交
1728

S
Stanislaw Gruszka 已提交
1729
	if (test_bit(S_EXIT_PENDING, &il->status))
1730 1731
		return -EINVAL;

S
Stanislaw Gruszka 已提交
1732
	if (!il_is_alive(il))
A
Abhijeet Kolekar 已提交
1733 1734 1735 1736 1737 1738 1739 1740
		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 已提交
1741
	staging_rxon->flags |= il3945_get_antenna_flags(il);
A
Abhijeet Kolekar 已提交
1742

S
Stanislaw Gruszka 已提交
1743
	rc = il_check_rxon_cmd(il, ctx);
A
Abhijeet Kolekar 已提交
1744
	if (rc) {
1745
		IL_ERR("Invalid RXON configuration.  Not committing.\n");
A
Abhijeet Kolekar 已提交
1746 1747 1748 1749
		return -EINVAL;
	}

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

		memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
1763 1764 1765 1766
		/*
		 * We do not commit tx power settings while channel changing,
		 * do it now if tx power changed.
		 */
S
Stanislaw Gruszka 已提交
1767
		il_set_tx_power(il, il->tx_power_next, false);
A
Abhijeet Kolekar 已提交
1768 1769 1770 1771 1772 1773 1774
		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 */
1775
	if (il_is_associated(il) && new_assoc) {
1776
		D_INFO("Toggling associated bit on current RXON\n");
A
Abhijeet Kolekar 已提交
1777 1778 1779 1780 1781 1782 1783 1784
		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;
1785
		rc = il_send_cmd_pdu(il, C_RXON,
S
Stanislaw Gruszka 已提交
1786
				      sizeof(struct il3945_rxon_cmd),
1787
				      &il->ctx.active);
A
Abhijeet Kolekar 已提交
1788 1789 1790 1791 1792

		/* 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;
1793
			IL_ERR("Error clearing ASSOC_MSK on current "
A
Abhijeet Kolekar 已提交
1794 1795 1796
				  "configuration (%d).\n", rc);
			return rc;
		}
S
Stanislaw Gruszka 已提交
1797
		il_clear_ucode_stations(il,
1798
					 &il->ctx);
S
Stanislaw Gruszka 已提交
1799
		il_restore_stations(il,
1800
					 &il->ctx);
A
Abhijeet Kolekar 已提交
1801 1802
	}

1803
	D_INFO("Sending RXON\n"
A
Abhijeet Kolekar 已提交
1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817
		       "* 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 已提交
1818
	il_set_rxon_hwcrypto(il, ctx, !il3945_mod_params.sw_crypto);
A
Abhijeet Kolekar 已提交
1819 1820

	/* Apply the new configuration */
1821
	rc = il_send_cmd_pdu(il, C_RXON,
S
Stanislaw Gruszka 已提交
1822
			      sizeof(struct il3945_rxon_cmd),
A
Abhijeet Kolekar 已提交
1823 1824
			      staging_rxon);
	if (rc) {
1825
		IL_ERR("Error setting new configuration (%d).\n", rc);
A
Abhijeet Kolekar 已提交
1826 1827 1828 1829 1830
		return rc;
	}

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

1831
	if (!new_assoc) {
S
Stanislaw Gruszka 已提交
1832
		il_clear_ucode_stations(il,
1833
					 &il->ctx);
S
Stanislaw Gruszka 已提交
1834
		il_restore_stations(il,
1835
					&il->ctx);
1836
	}
A
Abhijeet Kolekar 已提交
1837 1838 1839

	/* 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 已提交
1840
	rc = il_set_tx_power(il, il->tx_power_next, true);
A
Abhijeet Kolekar 已提交
1841
	if (rc) {
1842
		IL_ERR("Error setting Tx power (%d).\n", rc);
A
Abhijeet Kolekar 已提交
1843 1844 1845 1846
		return rc;
	}

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

	return 0;
}

Z
Zhu Yi 已提交
1856
/**
S
Stanislaw Gruszka 已提交
1857
 * il3945_reg_txpower_periodic -  called when time to check our temperature.
Z
Zhu Yi 已提交
1858 1859 1860 1861 1862 1863 1864 1865
 *
 * -- 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 已提交
1866
void il3945_reg_txpower_periodic(struct il_priv *il)
Z
Zhu Yi 已提交
1867 1868
{
	/* This will kick in the "brute force"
S
Stanislaw Gruszka 已提交
1869
	 * il3945_hw_reg_comp_txpower_temp() below */
S
Stanislaw Gruszka 已提交
1870
	if (!il3945_is_temp_calib_needed(il))
Z
Zhu Yi 已提交
1871 1872 1873 1874 1875
		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 已提交
1876
	il3945_hw_reg_comp_txpower_temp(il);
Z
Zhu Yi 已提交
1877 1878

 reschedule:
S
Stanislaw Gruszka 已提交
1879 1880
	queue_delayed_work(il->workqueue,
			   &il->_3945.thermal_periodic, REG_RECALIB_PERIOD * HZ);
Z
Zhu Yi 已提交
1881 1882
}

S
Stanislaw Gruszka 已提交
1883
static void il3945_bg_reg_txpower_periodic(struct work_struct *work)
Z
Zhu Yi 已提交
1884
{
S
Stanislaw Gruszka 已提交
1885
	struct il_priv *il = container_of(work, struct il_priv,
1886
					     _3945.thermal_periodic.work);
Z
Zhu Yi 已提交
1887

S
Stanislaw Gruszka 已提交
1888
	if (test_bit(S_EXIT_PENDING, &il->status))
Z
Zhu Yi 已提交
1889 1890
		return;

S
Stanislaw Gruszka 已提交
1891 1892 1893
	mutex_lock(&il->mutex);
	il3945_reg_txpower_periodic(il);
	mutex_unlock(&il->mutex);
Z
Zhu Yi 已提交
1894 1895 1896
}

/**
S
Stanislaw Gruszka 已提交
1897
 * il3945_hw_reg_get_ch_grp_idx - find the channel-group idx (0-4)
Z
Zhu Yi 已提交
1898 1899 1900 1901 1902 1903 1904 1905 1906
 * 				   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 已提交
1907
static u16 il3945_hw_reg_get_ch_grp_idx(struct il_priv *il,
S
Stanislaw Gruszka 已提交
1908
				       const struct il_channel_info *ch_info)
Z
Zhu Yi 已提交
1909
{
S
Stanislaw Gruszka 已提交
1910
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
S
Stanislaw Gruszka 已提交
1911
	struct il3945_eeprom_txpower_group *ch_grp = &eeprom->groups[0];
Z
Zhu Yi 已提交
1912
	u8 group;
S
Stanislaw Gruszka 已提交
1913
	u16 group_idx = 0;	/* based on factory calib frequencies */
Z
Zhu Yi 已提交
1914 1915
	u8 grp_channel;

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

1931
	D_POWER("Chnl %d mapped to grp %d\n", ch_info->channel,
S
Stanislaw Gruszka 已提交
1932 1933
			group_idx);
	return group_idx;
Z
Zhu Yi 已提交
1934 1935 1936
}

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

S
Stanislaw Gruszka 已提交
1956
	chnl_grp = &eeprom->groups[setting_idx];
Z
Zhu Yi 已提交
1957 1958 1959
	samples = chnl_grp->samples;
	for (i = 0; i < 5; i++) {
		if (power == samples[i].power) {
S
Stanislaw Gruszka 已提交
1960
			*new_idx = samples[i].gain_idx;
Z
Zhu Yi 已提交
1961 1962 1963 1964 1965
			return 0;
		}
	}

	if (power > samples[1].power) {
S
Stanislaw Gruszka 已提交
1966 1967
		idx0 = 0;
		idx1 = 1;
Z
Zhu Yi 已提交
1968
	} else if (power > samples[2].power) {
S
Stanislaw Gruszka 已提交
1969 1970
		idx0 = 1;
		idx1 = 2;
Z
Zhu Yi 已提交
1971
	} else if (power > samples[3].power) {
S
Stanislaw Gruszka 已提交
1972 1973
		idx0 = 2;
		idx1 = 3;
Z
Zhu Yi 已提交
1974
	} else {
S
Stanislaw Gruszka 已提交
1975 1976
		idx0 = 3;
		idx1 = 4;
Z
Zhu Yi 已提交
1977 1978
	}

S
Stanislaw Gruszka 已提交
1979
	denominator = (s32) samples[idx1].power - (s32) samples[idx0].power;
Z
Zhu Yi 已提交
1980 1981
	if (denominator == 0)
		return -EINVAL;
S
Stanislaw Gruszka 已提交
1982 1983
	gains0 = (s32) samples[idx0].gain_idx * (1 << 19);
	gains1 = (s32) samples[idx1].gain_idx * (1 << 19);
Z
Zhu Yi 已提交
1984
	res = gains0 + (gains1 - gains0) *
S
Stanislaw Gruszka 已提交
1985
	    ((s32) power - (s32) samples[idx0].power) / denominator +
Z
Zhu Yi 已提交
1986
	    (1 << 18);
S
Stanislaw Gruszka 已提交
1987
	*new_idx = res >> 19;
Z
Zhu Yi 已提交
1988 1989 1990
	return 0;
}

S
Stanislaw Gruszka 已提交
1991
static void il3945_hw_reg_init_channel_groups(struct il_priv *il)
Z
Zhu Yi 已提交
1992 1993
{
	u32 i;
S
Stanislaw Gruszka 已提交
1994
	s32 rate_idx;
S
Stanislaw Gruszka 已提交
1995
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
S
Stanislaw Gruszka 已提交
1996
	const struct il3945_eeprom_txpower_group *group;
Z
Zhu Yi 已提交
1997

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

S
Stanislaw Gruszka 已提交
2000
	for (i = 0; i < IL_NUM_TX_CALIB_GROUPS; i++) {
Z
Zhu Yi 已提交
2001 2002
		s8 *clip_pwrs;	/* table of power levels for each rate */
		s8 satur_pwr;	/* saturation power for each chnl group */
2003
		group = &eeprom->groups[i];
Z
Zhu Yi 已提交
2004 2005 2006

		/* sanity check on factory saturation power value */
		if (group->saturation_power < 40) {
2007
			IL_WARN("Error: saturation power is %d, "
Z
Zhu Yi 已提交
2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021
				    "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 已提交
2022
		clip_pwrs = (s8 *) il->_3945.clip_groups[i].clip_powers;
Z
Zhu Yi 已提交
2023 2024 2025 2026 2027

		/* 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 已提交
2028 2029 2030
		for (rate_idx = 0;
		     rate_idx < RATE_COUNT_3945; rate_idx++, clip_pwrs++) {
			switch (rate_idx) {
S
Stanislaw Gruszka 已提交
2031
			case RATE_36M_IDX_TBL:
Z
Zhu Yi 已提交
2032 2033 2034 2035 2036
				if (i == 0)	/* B/G */
					*clip_pwrs = satur_pwr;
				else	/* A */
					*clip_pwrs = satur_pwr - 5;
				break;
S
Stanislaw Gruszka 已提交
2037
			case RATE_48M_IDX_TBL:
Z
Zhu Yi 已提交
2038 2039 2040 2041 2042
				if (i == 0)
					*clip_pwrs = satur_pwr - 7;
				else
					*clip_pwrs = satur_pwr - 10;
				break;
S
Stanislaw Gruszka 已提交
2043
			case RATE_54M_IDX_TBL:
Z
Zhu Yi 已提交
2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057
				if (i == 0)
					*clip_pwrs = satur_pwr - 9;
				else
					*clip_pwrs = satur_pwr - 12;
				break;
			default:
				*clip_pwrs = satur_pwr;
				break;
			}
		}
	}
}

/**
S
Stanislaw Gruszka 已提交
2058
 * il3945_txpower_set_from_eeprom - Set channel power info based on EEPROM
Z
Zhu Yi 已提交
2059
 *
S
Stanislaw Gruszka 已提交
2060
 * Second pass (during init) to set up il->channel_info
Z
Zhu Yi 已提交
2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071
 *
 * 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 已提交
2072
int il3945_txpower_set_from_eeprom(struct il_priv *il)
Z
Zhu Yi 已提交
2073
{
S
Stanislaw Gruszka 已提交
2074 2075
	struct il_channel_info *ch_info = NULL;
	struct il3945_channel_power_info *pwr_info;
S
Stanislaw Gruszka 已提交
2076
	struct il3945_eeprom *eeprom = (struct il3945_eeprom *)il->eeprom;
S
Stanislaw Gruszka 已提交
2077 2078 2079
	int delta_idx;
	u8 rate_idx;
	u8 scan_tbl_idx;
Z
Zhu Yi 已提交
2080 2081 2082
	const s8 *clip_pwrs;	/* array of power levels for each rate */
	u8 gain, dsp_atten;
	s8 power;
S
Stanislaw Gruszka 已提交
2083
	u8 pwr_idx, base_pwr_idx, a_band;
Z
Zhu Yi 已提交
2084 2085 2086 2087 2088
	u8 i;
	int temperature;

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

S
Stanislaw Gruszka 已提交
2092
	il3945_hw_reg_init_channel_groups(il);
Z
Zhu Yi 已提交
2093 2094

	/* initialize Tx power info for each and every channel, 2.4 and 5.x */
S
Stanislaw Gruszka 已提交
2095
	for (i = 0, ch_info = il->channel_info; i < il->channel_count;
Z
Zhu Yi 已提交
2096
	     i++, ch_info++) {
S
Stanislaw Gruszka 已提交
2097 2098
		a_band = il_is_channel_a_band(ch_info);
		if (!il_is_channel_valid(ch_info))
Z
Zhu Yi 已提交
2099 2100
			continue;

S
Stanislaw Gruszka 已提交
2101 2102 2103
		/* 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 已提交
2104 2105

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

S
Stanislaw Gruszka 已提交
2108
		/* calculate power idx *adjustment* value according to
Z
Zhu Yi 已提交
2109
		 *  diff between current temperature and factory temperature */
S
Stanislaw Gruszka 已提交
2110 2111
		delta_idx = il3945_hw_reg_adjust_power_by_temp(temperature,
				eeprom->groups[ch_info->group_idx].
Z
Zhu Yi 已提交
2112 2113
				temperature);

S
Stanislaw Gruszka 已提交
2114 2115
		D_POWER("Delta idx for channel %d: %d [%d]\n",
				ch_info->channel, delta_idx, temperature +
S
Stanislaw Gruszka 已提交
2116
				IL_TEMP_CONVERT);
Z
Zhu Yi 已提交
2117 2118

		/* set tx power value for all OFDM rates */
S
Stanislaw Gruszka 已提交
2119 2120
		for (rate_idx = 0; rate_idx < IL_OFDM_RATES;
		     rate_idx++) {
2121
			s32 uninitialized_var(power_idx);
Z
Zhu Yi 已提交
2122 2123 2124 2125 2126
			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 已提交
2127
				     clip_pwrs[rate_idx]);
Z
Zhu Yi 已提交
2128

S
Stanislaw Gruszka 已提交
2129
			pwr_info = &ch_info->power_info[rate_idx];
Z
Zhu Yi 已提交
2130 2131

			/* get base (i.e. at factory-measured temperature)
S
Stanislaw Gruszka 已提交
2132 2133 2134
			 *    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 已提交
2135 2136
							 &power_idx);
			if (rc) {
S
Stanislaw Gruszka 已提交
2137
				IL_ERR("Invalid power idx\n");
Z
Zhu Yi 已提交
2138 2139
				return rc;
			}
S
Stanislaw Gruszka 已提交
2140
			pwr_info->base_power_idx = (u8) power_idx;
Z
Zhu Yi 已提交
2141 2142

			/* temperature compensate */
S
Stanislaw Gruszka 已提交
2143
			power_idx += delta_idx;
Z
Zhu Yi 已提交
2144 2145

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

S
Stanislaw Gruszka 已提交
2148
			/* fill 1 OFDM rate's il3945_channel_power_info struct */
Z
Zhu Yi 已提交
2149
			pwr_info->requested_power = pwr;
S
Stanislaw Gruszka 已提交
2150
			pwr_info->power_table_idx = (u8) power_idx;
Z
Zhu Yi 已提交
2151 2152 2153 2154 2155 2156 2157
			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 已提交
2158
		pwr_info = &ch_info->power_info[RATE_12M_IDX_TBL];
Z
Zhu Yi 已提交
2159
		power = pwr_info->requested_power +
S
Stanislaw Gruszka 已提交
2160
			IL_CCK_FROM_OFDM_POWER_DIFF;
S
Stanislaw Gruszka 已提交
2161
		pwr_idx = pwr_info->power_table_idx +
S
Stanislaw Gruszka 已提交
2162
			IL_CCK_FROM_OFDM_IDX_DIFF;
S
Stanislaw Gruszka 已提交
2163
		base_pwr_idx = pwr_info->base_power_idx +
S
Stanislaw Gruszka 已提交
2164
			IL_CCK_FROM_OFDM_IDX_DIFF;
Z
Zhu Yi 已提交
2165 2166

		/* stay within table range */
S
Stanislaw Gruszka 已提交
2167 2168 2169
		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 已提交
2170

S
Stanislaw Gruszka 已提交
2171
		/* fill each CCK rate's il3945_channel_power_info structure
Z
Zhu Yi 已提交
2172 2173
		 * NOTE:  All CCK-rate Txpwrs are the same for a given chnl!
		 * NOTE:  CCK rates start at end of OFDM rates! */
S
Stanislaw Gruszka 已提交
2174 2175 2176
		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 已提交
2177
			pwr_info->requested_power = power;
S
Stanislaw Gruszka 已提交
2178 2179
			pwr_info->power_table_idx = pwr_idx;
			pwr_info->base_power_idx = base_pwr_idx;
Z
Zhu Yi 已提交
2180 2181 2182 2183 2184
			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 已提交
2185 2186 2187
		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 已提交
2188
				RATE_1M_IDX_TBL : RATE_6M_IDX_TBL;
S
Stanislaw Gruszka 已提交
2189 2190
			il3945_hw_reg_set_scan_power(il, scan_tbl_idx,
				actual_idx, clip_pwrs, ch_info, a_band);
Z
Zhu Yi 已提交
2191 2192 2193 2194 2195 2196
		}
	}

	return 0;
}

S
Stanislaw Gruszka 已提交
2197
int il3945_hw_rxq_stop(struct il_priv *il)
Z
Zhu Yi 已提交
2198 2199 2200
{
	int rc;

2201 2202
	il_wr(il, FH39_RCSR_CONFIG(0), 0);
	rc = il_poll_bit(il, FH39_RSSR_STATUS,
2203
			FH39_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
Z
Zhu Yi 已提交
2204
	if (rc < 0)
2205
		IL_ERR("Can't stop Rx DMA.\n");
Z
Zhu Yi 已提交
2206 2207 2208 2209

	return 0;
}

S
Stanislaw Gruszka 已提交
2210
int il3945_hw_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq)
Z
Zhu Yi 已提交
2211 2212 2213
{
	int txq_id = txq->q.id;

S
Stanislaw Gruszka 已提交
2214
	struct il3945_shared *shared_data = il->_3945.shared_virt;
Z
Zhu Yi 已提交
2215 2216 2217

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

2218 2219
	il_wr(il, FH39_CBCC_CTRL(txq_id), 0);
	il_wr(il, FH39_CBCC_BASE(txq_id), 0);
2220

2221
	il_wr(il, FH39_TCSR_CONFIG(txq_id),
2222 2223 2224 2225 2226
		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 已提交
2227 2228

	/* fake read to flush all prev. writes */
2229
	_il_rd(il, FH39_TSSR_CBB_BASE);
Z
Zhu Yi 已提交
2230 2231 2232 2233

	return 0;
}

K
Kolekar, Abhijeet 已提交
2234 2235 2236
/*
 * HCMD utils
 */
S
Stanislaw Gruszka 已提交
2237
static u16 il3945_get_hcmd_size(u8 cmd_id, u16 len)
K
Kolekar, Abhijeet 已提交
2238 2239
{
	switch (cmd_id) {
2240
	case C_RXON:
S
Stanislaw Gruszka 已提交
2241
		return sizeof(struct il3945_rxon_cmd);
2242
	case C_POWER_TBL:
S
Stanislaw Gruszka 已提交
2243
		return sizeof(struct il3945_powertable_cmd);
K
Kolekar, Abhijeet 已提交
2244 2245 2246 2247 2248
	default:
		return len;
	}
}

2249

S
Stanislaw Gruszka 已提交
2250
static u16 il3945_build_addsta_hcmd(const struct il_addsta_cmd *cmd,
2251
								u8 *data)
2252
{
S
Stanislaw Gruszka 已提交
2253
	struct il3945_addsta_cmd *addsta = (struct il3945_addsta_cmd *)data;
2254 2255
	addsta->mode = cmd->mode;
	memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify));
S
Stanislaw Gruszka 已提交
2256
	memcpy(&addsta->key, &cmd->key, sizeof(struct il4965_keyinfo));
2257 2258 2259 2260 2261 2262 2263 2264
	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 已提交
2265
	return (u16)sizeof(struct il3945_addsta_cmd);
2266 2267
}

S
Stanislaw Gruszka 已提交
2268
static int il3945_add_bssid_station(struct il_priv *il,
2269 2270
				     const u8 *addr, u8 *sta_id_r)
{
2271
	struct il_rxon_context *ctx = &il->ctx;
2272 2273 2274 2275 2276
	int ret;
	u8 sta_id;
	unsigned long flags;

	if (sta_id_r)
S
Stanislaw Gruszka 已提交
2277
		*sta_id_r = IL_INVALID_STATION;
2278

S
Stanislaw Gruszka 已提交
2279
	ret = il_add_station_common(il, ctx, addr, 0, NULL, &sta_id);
2280
	if (ret) {
2281
		IL_ERR("Unable to add station %pM\n", addr);
2282 2283 2284 2285 2286 2287
		return ret;
	}

	if (sta_id_r)
		*sta_id_r = sta_id;

S
Stanislaw Gruszka 已提交
2288 2289 2290
	spin_lock_irqsave(&il->sta_lock, flags);
	il->stations[sta_id].used |= IL_STA_LOCAL;
	spin_unlock_irqrestore(&il->sta_lock, flags);
2291 2292 2293

	return 0;
}
S
Stanislaw Gruszka 已提交
2294
static int il3945_manage_ibss_station(struct il_priv *il,
2295 2296
				       struct ieee80211_vif *vif, bool add)
{
S
Stanislaw Gruszka 已提交
2297
	struct il_vif_priv *vif_priv = (void *)vif->drv_priv;
2298 2299 2300
	int ret;

	if (add) {
S
Stanislaw Gruszka 已提交
2301
		ret = il3945_add_bssid_station(il, vif->bss_conf.bssid,
2302
						&vif_priv->ibss_bssid_sta_id);
2303 2304 2305
		if (ret)
			return ret;

S
Stanislaw Gruszka 已提交
2306 2307
		il3945_sync_sta(il, vif_priv->ibss_bssid_sta_id,
				 (il->band == IEEE80211_BAND_5GHZ) ?
S
Stanislaw Gruszka 已提交
2308
				 RATE_6M_PLCP : RATE_1M_PLCP);
S
Stanislaw Gruszka 已提交
2309
		il3945_rate_scale_init(il->hw, vif_priv->ibss_bssid_sta_id);
2310 2311 2312 2313

		return 0;
	}

S
Stanislaw Gruszka 已提交
2314
	return il_remove_station(il, vif_priv->ibss_bssid_sta_id,
J
Johannes Berg 已提交
2315
				  vif->bss_conf.bssid);
2316
}
2317

Z
Zhu Yi 已提交
2318
/**
S
Stanislaw Gruszka 已提交
2319
 * il3945_init_hw_rate_table - Initialize the hardware rate fallback table
Z
Zhu Yi 已提交
2320
 */
S
Stanislaw Gruszka 已提交
2321
int il3945_init_hw_rate_table(struct il_priv *il)
Z
Zhu Yi 已提交
2322
{
S
Stanislaw Gruszka 已提交
2323
	int rc, i, idx, prev_idx;
S
Stanislaw Gruszka 已提交
2324
	struct il3945_rate_scaling_cmd rate_cmd = {
Z
Zhu Yi 已提交
2325 2326
		.reserved = {0, 0, 0},
	};
S
Stanislaw Gruszka 已提交
2327
	struct il3945_rate_scaling_info *table = rate_cmd.table;
Z
Zhu Yi 已提交
2328

S
Stanislaw Gruszka 已提交
2329
	for (i = 0; i < ARRAY_SIZE(il3945_rates); i++) {
S
Stanislaw Gruszka 已提交
2330
		idx = il3945_rates[i].table_rs_idx;
2331

S
Stanislaw Gruszka 已提交
2332
		table[idx].rate_n_flags =
S
Stanislaw Gruszka 已提交
2333
			il3945_hw_set_rate_n_flags(il3945_rates[i].plcp, 0);
S
Stanislaw Gruszka 已提交
2334 2335 2336 2337
		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 已提交
2338 2339
	}

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

		/* Don't fall back to CCK rates */
S
Stanislaw Gruszka 已提交
2351 2352
		table[RATE_12M_IDX_TBL].next_rate_idx =
						RATE_9M_IDX_TBL;
Z
Zhu Yi 已提交
2353 2354

		/* Don't drop out of OFDM rates */
S
Stanislaw Gruszka 已提交
2355
		table[RATE_6M_IDX_TBL].next_rate_idx =
S
Stanislaw Gruszka 已提交
2356
		    il3945_rates[IL_FIRST_OFDM_RATE].table_rs_idx;
Z
Zhu Yi 已提交
2357 2358
		break;

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

S
Stanislaw Gruszka 已提交
2364
		if (!(il->_3945.sta_supp_rates & IL_OFDM_RATES_MASK) &&
2365
		    il_is_associated(il)) {
2366

S
Stanislaw Gruszka 已提交
2367
			idx = IL_FIRST_CCK_RATE;
S
Stanislaw Gruszka 已提交
2368 2369
			for (i = RATE_6M_IDX_TBL;
			     i <= RATE_54M_IDX_TBL; i++)
S
Stanislaw Gruszka 已提交
2370 2371
				table[i].next_rate_idx =
					il3945_rates[idx].table_rs_idx;
2372

S
Stanislaw Gruszka 已提交
2373
			idx = RATE_11M_IDX_TBL;
2374
			/* CCK shouldn't fall back to OFDM... */
S
Stanislaw Gruszka 已提交
2375
			table[idx].next_rate_idx = RATE_5M_IDX_TBL;
2376
		}
Z
Zhu Yi 已提交
2377 2378 2379
		break;

	default:
2380
		WARN_ON(1);
Z
Zhu Yi 已提交
2381 2382 2383 2384 2385
		break;
	}

	/* Update the rate scaling for control frame Tx */
	rate_cmd.table_id = 0;
2386
	rc = il_send_cmd_pdu(il, C_RATE_SCALE, sizeof(rate_cmd),
Z
Zhu Yi 已提交
2387 2388 2389 2390 2391 2392
			      &rate_cmd);
	if (rc)
		return rc;

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

2397
/* Called when initializing driver */
S
Stanislaw Gruszka 已提交
2398
int il3945_hw_set_hw_params(struct il_priv *il)
Z
Zhu Yi 已提交
2399
{
S
Stanislaw Gruszka 已提交
2400
	memset((void *)&il->hw_params, 0,
S
Stanislaw Gruszka 已提交
2401
	       sizeof(struct il_hw_params));
Z
Zhu Yi 已提交
2402

S
Stanislaw Gruszka 已提交
2403 2404
	il->_3945.shared_virt =
		dma_alloc_coherent(&il->pci_dev->dev,
S
Stanislaw Gruszka 已提交
2405
				   sizeof(struct il3945_shared),
S
Stanislaw Gruszka 已提交
2406 2407
				   &il->_3945.shared_phys, GFP_KERNEL);
	if (!il->_3945.shared_virt) {
2408
		IL_ERR("failed to allocate pci memory\n");
Z
Zhu Yi 已提交
2409 2410 2411
		return -ENOMEM;
	}

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

S
Stanislaw Gruszka 已提交
2415 2416 2417 2418
	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;
2419
	il->hw_params.max_stations = IL3945_STATION_COUNT;
2420
	il->ctx.bcast_sta_id = IL3945_BROADCAST_ID;
2421

S
Stanislaw Gruszka 已提交
2422
	il->sta_key_max_num = STA_KEY_MAX_NUM;
2423

S
Stanislaw Gruszka 已提交
2424
	il->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
2425 2426
	il->hw_params.max_beacon_itrvl = IL39_MAX_UCODE_BEACON_INTERVAL;
	il->hw_params.beacon_time_tsf_bits = IL3945_EXT_BEACON_TIME_POS;
2427

Z
Zhu Yi 已提交
2428 2429 2430
	return 0;
}

S
Stanislaw Gruszka 已提交
2431
unsigned int il3945_hw_get_beacon_cmd(struct il_priv *il,
S
Stanislaw Gruszka 已提交
2432
			  struct il3945_frame *frame, u8 rate)
Z
Zhu Yi 已提交
2433
{
S
Stanislaw Gruszka 已提交
2434
	struct il3945_tx_beacon_cmd *tx_beacon_cmd;
Z
Zhu Yi 已提交
2435 2436
	unsigned int frame_size;

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

2440
	tx_beacon_cmd->tx.sta_id =
2441
		il->ctx.bcast_sta_id;
Z
Zhu Yi 已提交
2442 2443
	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;

S
Stanislaw Gruszka 已提交
2444
	frame_size = il3945_fill_beacon_frame(il,
Z
Zhu Yi 已提交
2445 2446 2447 2448 2449 2450 2451 2452 2453 2454
				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 已提交
2455
	/* supp_rates[0] == OFDM start at IL_FIRST_OFDM_RATE*/
2456
	tx_beacon_cmd->tx.supp_rates[0] =
S
Stanislaw Gruszka 已提交
2457
		(IL_OFDM_BASIC_RATES_MASK >> IL_FIRST_OFDM_RATE) & 0xFF;
2458

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

S
Stanislaw Gruszka 已提交
2462
	return sizeof(struct il3945_tx_beacon_cmd) + frame_size;
Z
Zhu Yi 已提交
2463 2464
}

2465
void il3945_hw_handler_setup(struct il_priv *il)
Z
Zhu Yi 已提交
2466
{
S
Stanislaw Gruszka 已提交
2467 2468
	il->handlers[C_TX] = il3945_hdl_tx;
	il->handlers[N_3945_RX] = il3945_hdl_rx;
Z
Zhu Yi 已提交
2469 2470
}

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

S
Stanislaw Gruszka 已提交
2477
void il3945_hw_cancel_deferred_work(struct il_priv *il)
Z
Zhu Yi 已提交
2478
{
S
Stanislaw Gruszka 已提交
2479
	cancel_delayed_work(&il->_3945.thermal_periodic);
Z
Zhu Yi 已提交
2480 2481
}

K
Kolekar, Abhijeet 已提交
2482
/* check contents of special bootstrap uCode SRAM */
S
Stanislaw Gruszka 已提交
2483
static int il3945_verify_bsm(struct il_priv *il)
K
Kolekar, Abhijeet 已提交
2484
 {
S
Stanislaw Gruszka 已提交
2485 2486
	__le32 *image = il->ucode_boot.v_addr;
	u32 len = il->ucode_boot.len;
K
Kolekar, Abhijeet 已提交
2487 2488 2489
	u32 reg;
	u32 val;

2490
	D_INFO("Begin verify bsm\n");
K
Kolekar, Abhijeet 已提交
2491 2492

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

2508
	D_INFO("BSM bootstrap uCode image OK\n");
K
Kolekar, Abhijeet 已提交
2509 2510 2511 2512

	return 0;
}

2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527

/******************************************************************************
 *
 * 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 已提交
2528
static int il3945_eeprom_acquire_semaphore(struct il_priv *il)
2529
{
S
Stanislaw Gruszka 已提交
2530
	_il_clear_bit(il, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
2531 2532 2533 2534
	return 0;
}


S
Stanislaw Gruszka 已提交
2535
static void il3945_eeprom_release_semaphore(struct il_priv *il)
2536 2537 2538 2539
{
	return;
}

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

2585
	D_INFO("Begin load bsm\n");
K
Kolekar, Abhijeet 已提交
2586 2587

	/* make sure bootstrap program is no larger than BSM's SRAM size */
2588
	if (len > IL39_MAX_BSM_SIZE)
K
Kolekar, Abhijeet 已提交
2589 2590 2591 2592
		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 已提交
2593
	* NOTE:  il3945_initialize_alive_start() will replace these values,
K
Kolekar, Abhijeet 已提交
2594 2595
	*        after the "initialize" uCode has run, to point to
	*        runtime/protocol instructions and backup data cache. */
S
Stanislaw Gruszka 已提交
2596 2597 2598 2599
	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 已提交
2600

2601 2602 2603 2604
	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 已提交
2605 2606 2607 2608 2609

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

S
Stanislaw Gruszka 已提交
2613
	rc = il3945_verify_bsm(il);
M
Mohamed Abbas 已提交
2614
	if (rc)
K
Kolekar, Abhijeet 已提交
2615 2616 2617
		return rc;

	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
2618 2619
	il_wr_prph(il, BSM_WR_MEM_SRC_REG, 0x0);
	il_wr_prph(il, BSM_WR_MEM_DST_REG,
2620
				 IL39_RTC_INST_LOWER_BOUND);
2621
	il_wr_prph(il, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
K
Kolekar, Abhijeet 已提交
2622 2623 2624

	/* Load bootstrap code into instruction SRAM now,
	 *   to prepare to load "initialize" uCode */
2625
	il_wr_prph(il, BSM_WR_CTRL_REG,
K
Kolekar, Abhijeet 已提交
2626 2627 2628 2629
		BSM_WR_CTRL_REG_BIT_START);

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

	/* Enable future boot loads whenever power management unit triggers it
	 *   (e.g. when powering back up after power-save shutdown) */
2644
	il_wr_prph(il, BSM_WR_CTRL_REG,
K
Kolekar, Abhijeet 已提交
2645 2646 2647 2648 2649
		BSM_WR_CTRL_REG_BIT_START_EN);

	return 0;
}

S
Stanislaw Gruszka 已提交
2650 2651 2652
static struct il_hcmd_ops il3945_hcmd = {
	.rxon_assoc = il3945_send_rxon_assoc,
	.commit_rxon = il3945_commit_rxon,
2653 2654
};

S
Stanislaw Gruszka 已提交
2655 2656 2657 2658 2659 2660
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 已提交
2661
	.apm_ops = {
S
Stanislaw Gruszka 已提交
2662 2663
		.init = il3945_apm_init,
		.config = il3945_nic_config,
K
Kolekar, Abhijeet 已提交
2664
	},
2665 2666 2667 2668 2669 2670 2671
	.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,
2672 2673
			EEPROM_REGULATORY_BAND_NO_HT40,
			EEPROM_REGULATORY_BAND_NO_HT40,
2674
		},
S
Stanislaw Gruszka 已提交
2675 2676
		.acquire_semaphore = il3945_eeprom_acquire_semaphore,
		.release_semaphore = il3945_eeprom_release_semaphore,
2677
	},
S
Stanislaw Gruszka 已提交
2678 2679
	.send_tx_power	= il3945_send_tx_power,
	.is_valid_rtc_data_addr = il3945_hw_valid_rtc_data_addr,
A
Abhijeet Kolekar 已提交
2680 2681

	.debugfs_ops = {
S
Stanislaw Gruszka 已提交
2682 2683 2684
		.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 已提交
2685
	},
K
Kolekar, Abhijeet 已提交
2686 2687
};

S
Stanislaw Gruszka 已提交
2688 2689 2690 2691
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,
2692 2693
};

S
Stanislaw Gruszka 已提交
2694 2695 2696 2697 2698
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 已提交
2699 2700
};

S
Stanislaw Gruszka 已提交
2701 2702 2703 2704 2705 2706 2707
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 已提交
2708 2709
};

S
Stanislaw Gruszka 已提交
2710
static struct il_base_params il3945_base_params = {
2711 2712
	.eeprom_size = IL3945_EEPROM_IMG_SIZE,
	.num_of_queues = IL39_NUM_QUEUES,
2713 2714 2715
	.pll_cfg_val = CSR39_ANA_PLL_CFG_VAL,
	.set_l0s = false,
	.use_bsm = true,
2716
	.led_compensation = 64,
S
Stanislaw Gruszka 已提交
2717
	.wd_timeout = IL_DEF_WD_TIMEOUT,
T
Tomas Winkler 已提交
2718 2719
};

S
Stanislaw Gruszka 已提交
2720
static struct il_cfg il3945_bg_cfg = {
2721
	.name = "3945BG",
2722 2723 2724
	.fw_name_pre = IL3945_FW_PRE,
	.ucode_api_max = IL3945_UCODE_API_MAX,
	.ucode_api_min = IL3945_UCODE_API_MIN,
S
Stanislaw Gruszka 已提交
2725
	.sku = IL_SKU_G,
2726
	.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
S
Stanislaw Gruszka 已提交
2727 2728 2729 2730
	.ops = &il3945_ops,
	.mod_params = &il3945_mod_params,
	.base_params = &il3945_base_params,
	.led_mode = IL_LED_BLINK,
2731 2732
};

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

S
Stanislaw Gruszka 已提交
2746 2747 2748 2749 2750 2751 2752
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 已提交
2753 2754 2755
	{0}
};

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