3945.c 76.1 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-3945-fh.h"
44
#include "iwl-commands.h"
45
#include "iwl-sta.h"
Z
Zhu Yi 已提交
46
#include "iwl-3945.h"
47
#include "iwl-eeprom.h"
K
Kolekar, Abhijeet 已提交
48
#include "iwl-core.h"
49
#include "iwl-helpers.h"
J
Johannes Berg 已提交
50
#include "iwl-led.h"
A
Abhijeet Kolekar 已提交
51
#include "iwl-3945-debugfs.h"
Z
Zhu Yi 已提交
52

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

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

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

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

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

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

S
Stanislaw Gruszka 已提交
191 192
	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 已提交
193

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

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

}

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

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

221
#ifdef CONFIG_IWLEGACY_DEBUG
222
#define TX_STATUS_ENTRY(x) case TX_3945_STATUS_FAIL_ ## x: return #x
223

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

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

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

280 281 282 283 284 285 286
	default:
		break;
	}

	return next_rate;
}

287 288

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

302
	BUG_ON(txq_id == IL39_CMD_QUEUE_NUM);
303

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

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

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

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

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

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

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

	fail = tx_resp->failure_frame;
354 355 356

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

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

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

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

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



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

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

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

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

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

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

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

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


452 453 454 455 456 457
/******************************************************************************
 *
 * Misc. internal state and helper functions
 *
 ******************************************************************************/

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

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

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

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

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

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

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

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

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

S
Stanislaw Gruszka 已提交
524
#define IL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
525

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

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

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

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

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

570

Z
Zhu Yi 已提交
571 572

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	count++;

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

	return 0;
}

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

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

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

Z
Zhu Yi 已提交
665 666
	/* unmap chunks if any */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return 0;
}

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

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

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

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

825 826 827 828
	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 已提交
829

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

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


	return 0;
}

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

S
Stanislaw Gruszka 已提交
856
	il3945_hw_txq_ctx_free(il);
Z
Zhu Yi 已提交
857

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

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

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

	return rc;

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

887

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

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

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

K
Kolekar, Abhijeet 已提交
908 909
	return ret;
}
Z
Zhu Yi 已提交
910

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

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

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

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

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

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

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

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

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

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

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

S
Stanislaw Gruszka 已提交
983
	il3945_set_pwr_vmain(il);
K
Kolekar, Abhijeet 已提交
984

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

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

S
Stanislaw Gruszka 已提交
997
	il3945_rx_replenish(il);
Z
Zhu Yi 已提交
998

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


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

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

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

S
Stanislaw Gruszka 已提交
1013
	set_bit(STATUS_INIT, &il->status);
Z
Zhu Yi 已提交
1014 1015 1016 1017 1018

	return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

	return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return 0;
}

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

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

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

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

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

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

	return rc;
}

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

S
Stanislaw Gruszka 已提交
1731
	if (test_bit(STATUS_EXIT_PENDING, &il->status))
1732 1733
		return -EINVAL;

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

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

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

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

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

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

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

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

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

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

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

	return 0;
}

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

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

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

S
Stanislaw Gruszka 已提交
1890
	if (test_bit(STATUS_EXIT_PENDING, &il->status))
Z
Zhu Yi 已提交
1891 1892
		return;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

S
Stanislaw Gruszka 已提交
2094
	il3945_hw_reg_init_channel_groups(il);
Z
Zhu Yi 已提交
2095 2096

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

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

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

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

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

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

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

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

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

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

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

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

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

	return 0;
}

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

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

	return 0;
}

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

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

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

2220 2221
	il_wr(il, FH39_CBCC_CTRL(txq_id), 0);
	il_wr(il, FH39_CBCC_BASE(txq_id), 0);
2222

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

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

	return 0;
}

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

2251

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

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

	if (sta_id_r)
S
Stanislaw Gruszka 已提交
2279
		*sta_id_r = IL_INVALID_STATION;
2280

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

	if (sta_id_r)
		*sta_id_r = sta_id;

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

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

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

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

		return 0;
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

	/* Update the rate scaling for data frame Tx */
	rate_cmd.table_id = 1;
S
Stanislaw Gruszka 已提交
2395
	return il_send_cmd_pdu(il, REPLY_RATE_SCALE, sizeof(rate_cmd),
Z
Zhu Yi 已提交
2396 2397 2398
				&rate_cmd);
}

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

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

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

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

S
Stanislaw Gruszka 已提交
2424
	il->sta_key_max_num = STA_KEY_MAX_NUM;
2425

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

Z
Zhu Yi 已提交
2430 2431 2432
	return 0;
}

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

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

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

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

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

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

S
Stanislaw Gruszka 已提交
2467
void il3945_hw_rx_handler_setup(struct il_priv *il)
Z
Zhu Yi 已提交
2468
{
S
Stanislaw Gruszka 已提交
2469 2470
	il->rx_handlers[REPLY_TX] = il3945_rx_reply_tx;
	il->rx_handlers[REPLY_3945_RX] = il3945_rx_reply_rx;
Z
Zhu Yi 已提交
2471 2472
}

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

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

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

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

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

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

	return 0;
}

2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529

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


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

K
Kolekar, Abhijeet 已提交
2542
 /**
S
Stanislaw Gruszka 已提交
2543
  * il3945_load_bsm - Load bootstrap instructions
K
Kolekar, Abhijeet 已提交
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 2572 2573
  *
  * 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 已提交
2574
static int il3945_load_bsm(struct il_priv *il)
K
Kolekar, Abhijeet 已提交
2575
{
S
Stanislaw Gruszka 已提交
2576 2577
	__le32 *image = il->ucode_boot.v_addr;
	u32 len = il->ucode_boot.len;
K
Kolekar, Abhijeet 已提交
2578 2579 2580 2581 2582 2583 2584 2585 2586
	dma_addr_t pinst;
	dma_addr_t pdata;
	u32 inst_len;
	u32 data_len;
	int rc;
	int i;
	u32 done;
	u32 reg_offset;

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

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

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

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

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

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

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

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

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

	return 0;
}

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

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

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

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

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

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

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

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

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

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

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