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

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

42
#include "commands.h"
43
#include "iwl-sta.h"
44
#include "iwl-eeprom.h"
45
#include "common.h"
46
#include "iwl-helpers.h"
J
Johannes Berg 已提交
47
#include "iwl-led.h"
48
#include "3945.h"
Z
Zhu Yi 已提交
49

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

	return next_rate;
}

284 285

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

299
	BUG_ON(txq_id == IL39_CMD_QUEUE_NUM);
300

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

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

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

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

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

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

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

	fail = tx_resp->failure_frame;
351 352 353

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

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

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

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

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



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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

567

Z
Zhu Yi 已提交
568 569

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	count++;

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

	return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return 0;
}

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

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

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

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

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

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

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


	return 0;
}

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

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

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

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

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

	return rc;

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

884

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

	return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* 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 已提交
1155
static struct il3945_tx_power power_gain_table[2][IL_MAX_GAIN_ENTRIES] = {
Z
Zhu Yi 已提交
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315
	{
	 {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 已提交
1316
static inline u8 il3945_hw_reg_fix_power_idx(int idx)
Z
Zhu Yi 已提交
1317
{
S
Stanislaw Gruszka 已提交
1318
	if (idx < 0)
Z
Zhu Yi 已提交
1319
		return 0;
S
Stanislaw Gruszka 已提交
1320
	if (idx >= IL_MAX_GAIN_ENTRIES)
S
Stanislaw Gruszka 已提交
1321
		return IL_MAX_GAIN_ENTRIES - 1;
S
Stanislaw Gruszka 已提交
1322
	return (u8) idx;
Z
Zhu Yi 已提交
1323 1324 1325 1326 1327 1328
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

	return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return 0;
}

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

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

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

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

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

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

	return rc;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

	return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return 0;
}

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

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

	return 0;
}

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

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

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

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

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

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

	return 0;
}

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

2248

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

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

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

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

	if (sta_id_r)
		*sta_id_r = sta_id;

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

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

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

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

		return 0;
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return 0;
}

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

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


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

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

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

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

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

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

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

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

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

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

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

	return 0;
}

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

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

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

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

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

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

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

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

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

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

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