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

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <asm/unaligned.h>

40
#include "common.h"
41
#include "4965.h"
42

43 44 45 46 47 48
/**
 * il_verify_inst_sparse - verify runtime uCode image in card vs. host,
 *   using sample data 100 bytes apart.  If these sample points are good,
 *   it's a pretty good bet that everything between them is good, too.
 */
static int
49
il4965_verify_inst_sparse(struct il_priv *il, __le32 * image, u32 len)
50 51 52 53 54 55 56 57
{
	u32 val;
	int ret = 0;
	u32 errcnt = 0;
	u32 i;

	D_INFO("ucode inst image size is %u\n", len);

58
	for (i = 0; i < len; i += 100, image += 100 / sizeof(u32)) {
59 60 61
		/* read data comes through single port, auto-incr addr */
		/* NOTE: Use the debugless read so we don't flood kernel log
		 * if IL_DL_IO is set */
62
		il_wr(il, HBUS_TARG_MEM_RADDR, i + IL4965_RTC_INST_LOWER_BOUND);
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
		val = _il_rd(il, HBUS_TARG_MEM_RDAT);
		if (val != le32_to_cpu(*image)) {
			ret = -EIO;
			errcnt++;
			if (errcnt >= 3)
				break;
		}
	}

	return ret;
}

/**
 * il4965_verify_inst_full - verify runtime uCode image in card vs. host,
 *     looking at all data.
 */
79 80
static int
il4965_verify_inst_full(struct il_priv *il, __le32 * image, u32 len)
81 82 83 84 85 86 87 88
{
	u32 val;
	u32 save_len = len;
	int ret = 0;
	u32 errcnt;

	D_INFO("ucode inst image size is %u\n", len);

89
	il_wr(il, HBUS_TARG_MEM_RADDR, IL4965_RTC_INST_LOWER_BOUND);
90 91 92 93 94 95 96 97 98

	errcnt = 0;
	for (; len > 0; len -= sizeof(u32), image++) {
		/* read data comes through single port, auto-incr addr */
		/* NOTE: Use the debugless read so we don't flood kernel log
		 * if IL_DL_IO is set */
		val = _il_rd(il, HBUS_TARG_MEM_RDAT);
		if (val != le32_to_cpu(*image)) {
			IL_ERR("uCode INST section is invalid at "
99 100
			       "offset 0x%x, is 0x%x, s/b 0x%x\n",
			       save_len - len, val, le32_to_cpu(*image));
101 102 103 104 105 106 107 108
			ret = -EIO;
			errcnt++;
			if (errcnt >= 20)
				break;
		}
	}

	if (!errcnt)
109
		D_INFO("ucode image in INSTRUCTION memory is good\n");
110 111 112 113 114 115 116 117

	return ret;
}

/**
 * il4965_verify_ucode - determine which instruction image is in SRAM,
 *    and verify its contents
 */
118 119
int
il4965_verify_ucode(struct il_priv *il)
120 121 122 123 124 125
{
	__le32 *image;
	u32 len;
	int ret;

	/* Try bootstrap */
126
	image = (__le32 *) il->ucode_boot.v_addr;
127 128 129 130 131 132 133 134
	len = il->ucode_boot.len;
	ret = il4965_verify_inst_sparse(il, image, len);
	if (!ret) {
		D_INFO("Bootstrap uCode is good in inst SRAM\n");
		return 0;
	}

	/* Try initialize */
135
	image = (__le32 *) il->ucode_init.v_addr;
136 137 138 139 140 141 142 143
	len = il->ucode_init.len;
	ret = il4965_verify_inst_sparse(il, image, len);
	if (!ret) {
		D_INFO("Initialize uCode is good in inst SRAM\n");
		return 0;
	}

	/* Try runtime/protocol */
144
	image = (__le32 *) il->ucode_code.v_addr;
145 146 147 148 149 150 151 152 153 154 155 156
	len = il->ucode_code.len;
	ret = il4965_verify_inst_sparse(il, image, len);
	if (!ret) {
		D_INFO("Runtime uCode is good in inst SRAM\n");
		return 0;
	}

	IL_ERR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");

	/* Since nothing seems to match, show first several data entries in
	 * instruction SRAM, so maybe visual inspection will give a clue.
	 * Selection of bootstrap image (vs. other images) is arbitrary. */
157
	image = (__le32 *) il->ucode_boot.v_addr;
158 159 160 161 162 163
	len = il->ucode_boot.len;
	ret = il4965_verify_inst_full(il, image, len);

	return ret;
}

164 165 166 167 168 169 170 171 172 173 174 175
/******************************************************************************
 *
 * EEPROM related functions
 *
******************************************************************************/

/*
 * The device's EEPROM semaphore prevents conflicts between driver and uCode
 * when accessing the EEPROM; each access 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 the semaphore.
 */
176 177
int
il4965_eeprom_acquire_semaphore(struct il_priv *il)
178 179 180 181 182 183 184
{
	u16 count;
	int ret;

	for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
		/* Request semaphore */
		il_set_bit(il, CSR_HW_IF_CONFIG_REG,
185
			   CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
186 187

		/* See if we got it */
188 189 190 191 192
		ret =
		    _il_poll_bit(il, CSR_HW_IF_CONFIG_REG,
				 CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
				 CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
				 EEPROM_SEM_TIMEOUT);
193 194 195 196 197 198 199
		if (ret >= 0)
			return ret;
	}

	return ret;
}

200 201
void
il4965_eeprom_release_semaphore(struct il_priv *il)
202 203
{
	il_clear_bit(il, CSR_HW_IF_CONFIG_REG,
204
		     CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
205 206 207

}

208 209
int
il4965_eeprom_check_version(struct il_priv *il)
210 211 212 213 214
{
	u16 eeprom_ver;
	u16 calib_ver;

	eeprom_ver = il_eeprom_query16(il, EEPROM_VERSION);
215
	calib_ver = il_eeprom_query16(il, EEPROM_4965_CALIB_VERSION_OFFSET);
216 217 218 219 220

	if (eeprom_ver < il->cfg->eeprom_ver ||
	    calib_ver < il->cfg->eeprom_calib_ver)
		goto err;

221
	IL_INFO("device EEPROM VER=0x%x, CALIB=0x%x\n", eeprom_ver, calib_ver);
222 223 224 225

	return 0;
err:
	IL_ERR("Unsupported (too old) EEPROM VER=0x%x < 0x%x "
226 227
	       "CALIB=0x%x < 0x%x\n", eeprom_ver, il->cfg->eeprom_ver,
	       calib_ver, il->cfg->eeprom_calib_ver);
228 229 230 231
	return -EINVAL;

}

232 233
void
il4965_eeprom_get_mac(const struct il_priv *il, u8 * mac)
234 235
{
	const u8 *addr = il_eeprom_query_addr(il,
236
					      EEPROM_MAC_ADDRESS);
237 238 239
	memcpy(mac, addr, ETH_ALEN);
}

240 241 242 243 244
/* Send led command */
static int
il4965_send_led_cmd(struct il_priv *il, struct il_led_cmd *led_cmd)
{
	struct il_host_cmd cmd = {
245
		.id = C_LEDS,
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
		.len = sizeof(struct il_led_cmd),
		.data = led_cmd,
		.flags = CMD_ASYNC,
		.callback = NULL,
	};
	u32 reg;

	reg = _il_rd(il, CSR_LED_REG);
	if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
		_il_wr(il, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);

	return il_send_cmd(il, &cmd);
}

/* Set led register off */
261 262
void
il4965_led_enable(struct il_priv *il)
263 264 265 266 267 268 269 270
{
	_il_wr(il, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
}

const struct il_led_ops il4965_led_ops = {
	.cmd = il4965_send_led_cmd,
};

S
Stanislaw Gruszka 已提交
271 272
static int il4965_send_tx_power(struct il_priv *il);
static int il4965_hw_get_temperature(struct il_priv *il);
273 274

/* Highest firmware API version supported */
275
#define IL4965_UCODE_API_MAX 2
276 277

/* Lowest firmware API version supported */
278
#define IL4965_UCODE_API_MIN 2
279

280 281 282
#define IL4965_FW_PRE "iwlwifi-4965-"
#define _IL4965_MODULE_FIRMWARE(api) IL4965_FW_PRE #api ".ucode"
#define IL4965_MODULE_FIRMWARE(api) _IL4965_MODULE_FIRMWARE(api)
283 284

/* check contents of special bootstrap uCode SRAM */
285 286
static int
il4965_verify_bsm(struct il_priv *il)
287
{
S
Stanislaw Gruszka 已提交
288 289
	__le32 *image = il->ucode_boot.v_addr;
	u32 len = il->ucode_boot.len;
290 291 292
	u32 reg;
	u32 val;

293
	D_INFO("Begin verify bsm\n");
294 295

	/* verify BSM SRAM contents */
296
	val = il_rd_prph(il, BSM_WR_DWCOUNT_REG);
297
	for (reg = BSM_SRAM_LOWER_BOUND; reg < BSM_SRAM_LOWER_BOUND + len;
298
	     reg += sizeof(u32), image++) {
299
		val = il_rd_prph(il, reg);
300
		if (val != le32_to_cpu(*image)) {
301
			IL_ERR("BSM uCode verification failed at "
302 303 304
			       "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));
305 306 307 308
			return -EIO;
		}
	}

309
	D_INFO("BSM bootstrap uCode image OK\n");
310 311 312 313 314

	return 0;
}

/**
S
Stanislaw Gruszka 已提交
315
 * il4965_load_bsm - Load bootstrap instructions
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
 *
 * 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.
 */
346 347
static int
il4965_load_bsm(struct il_priv *il)
348
{
S
Stanislaw Gruszka 已提交
349 350
	__le32 *image = il->ucode_boot.v_addr;
	u32 len = il->ucode_boot.len;
351 352 353 354 355 356 357 358 359
	dma_addr_t pinst;
	dma_addr_t pdata;
	u32 inst_len;
	u32 data_len;
	int i;
	u32 done;
	u32 reg_offset;
	int ret;

360
	D_INFO("Begin load bsm\n");
361

S
Stanislaw Gruszka 已提交
362
	il->ucode_type = UCODE_RT;
363 364

	/* make sure bootstrap program is no larger than BSM's SRAM size */
365
	if (len > IL49_MAX_BSM_SIZE)
366 367 368 369
		return -EINVAL;

	/* Tell bootstrap uCode where to find the "Initialize" uCode
	 *   in host DRAM ... host DRAM physical address bits 35:4 for 4965.
S
Stanislaw Gruszka 已提交
370
	 * NOTE:  il_init_alive_start() will replace these values,
371 372 373
	 *        after the "initialize" uCode has run, to point to
	 *        runtime/protocol instructions and backup data cache.
	 */
S
Stanislaw Gruszka 已提交
374 375 376 377
	pinst = il->ucode_init.p_addr >> 4;
	pdata = il->ucode_init_data.p_addr >> 4;
	inst_len = il->ucode_init.len;
	data_len = il->ucode_init_data.len;
378

379 380 381 382
	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);
383 384 385 386 387

	/* 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++)
388
		_il_wr_prph(il, reg_offset, le32_to_cpu(*image));
389

S
Stanislaw Gruszka 已提交
390
	ret = il4965_verify_bsm(il);
391 392 393 394
	if (ret)
		return ret;

	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
395
	il_wr_prph(il, BSM_WR_MEM_SRC_REG, 0x0);
396
	il_wr_prph(il, BSM_WR_MEM_DST_REG, IL49_RTC_INST_LOWER_BOUND);
397
	il_wr_prph(il, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
398 399 400

	/* Load bootstrap code into instruction SRAM now,
	 *   to prepare to load "initialize" uCode */
401
	il_wr_prph(il, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START);
402 403 404

	/* Wait for load of bootstrap uCode to finish */
	for (i = 0; i < 100; i++) {
405
		done = il_rd_prph(il, BSM_WR_CTRL_REG);
406 407 408 409 410
		if (!(done & BSM_WR_CTRL_REG_BIT_START))
			break;
		udelay(10);
	}
	if (i < 100)
411
		D_INFO("BSM write complete, poll %d iterations\n", i);
412
	else {
413
		IL_ERR("BSM write did not complete!\n");
414 415 416 417 418
		return -EIO;
	}

	/* Enable future boot loads whenever power management unit triggers it
	 *   (e.g. when powering back up after power-save shutdown) */
419
	il_wr_prph(il, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN);
420 421 422 423 424

	return 0;
}

/**
S
Stanislaw Gruszka 已提交
425
 * il4965_set_ucode_ptrs - Set uCode address location
426 427 428 429 430 431 432
 *
 * Tell initialization uCode where to find runtime uCode.
 *
 * BSM registers initially contain pointers to initialization uCode.
 * We need to replace them to load runtime uCode inst and data,
 * and to save runtime data when powering down.
 */
433 434
static int
il4965_set_ucode_ptrs(struct il_priv *il)
435 436 437 438 439 440
{
	dma_addr_t pinst;
	dma_addr_t pdata;
	int ret = 0;

	/* bits 35:4 for 4965 */
S
Stanislaw Gruszka 已提交
441 442
	pinst = il->ucode_code.p_addr >> 4;
	pdata = il->ucode_data_backup.p_addr >> 4;
443 444

	/* Tell bootstrap uCode where to find image to load */
445 446
	il_wr_prph(il, BSM_DRAM_INST_PTR_REG, pinst);
	il_wr_prph(il, BSM_DRAM_DATA_PTR_REG, pdata);
447
	il_wr_prph(il, BSM_DRAM_DATA_BYTECOUNT_REG, il->ucode_data.len);
448 449 450

	/* Inst byte count must be last to set up, bit 31 signals uCode
	 *   that all new ptr/size info is in place */
451
	il_wr_prph(il, BSM_DRAM_INST_BYTECOUNT_REG,
452
		   il->ucode_code.len | BSM_DRAM_INST_LOAD);
453
	D_INFO("Runtime uCode pointers are set.\n");
454 455 456 457 458

	return ret;
}

/**
459
 * il4965_init_alive_start - Called after N_ALIVE notification received
460
 *
461
 * Called after N_ALIVE notification received from "initialize" uCode.
462 463
 *
 * The 4965 "initialize" ALIVE reply contains calibration data for:
S
Stanislaw Gruszka 已提交
464
 *   Voltage, temperature, and MIMO tx gain correction, now stored in il
465 466 467 468
 *   (3945 does not contain this data).
 *
 * Tell "initialize" uCode to go ahead and load the runtime uCode.
*/
469 470
static void
il4965_init_alive_start(struct il_priv *il)
471 472 473 474
{
	/* Bootstrap uCode has loaded initialize uCode ... verify inst image.
	 * This is a paranoid check, because we would not have gotten the
	 * "initialize" alive if code weren't properly loaded.  */
S
Stanislaw Gruszka 已提交
475
	if (il4965_verify_ucode(il)) {
476 477
		/* Runtime instruction load was bad;
		 * take it all the way back down so we can try again */
478
		D_INFO("Bad \"initialize\" uCode load.\n");
479 480 481 482
		goto restart;
	}

	/* Calculate temperature */
S
Stanislaw Gruszka 已提交
483
	il->temperature = il4965_hw_get_temperature(il);
484 485 486 487

	/* Send pointers to protocol/runtime uCode image ... init code will
	 * load and launch runtime uCode, which will send us another "Alive"
	 * notification. */
488
	D_INFO("Initialization Alive received.\n");
S
Stanislaw Gruszka 已提交
489
	if (il4965_set_ucode_ptrs(il)) {
490 491
		/* Runtime instruction load won't happen;
		 * take it all the way back down so we can try again */
492
		D_INFO("Couldn't set up uCode pointers.\n");
493 494 495 496 497
		goto restart;
	}
	return;

restart:
S
Stanislaw Gruszka 已提交
498
	queue_work(il->workqueue, &il->restart);
499 500
}

501 502
static bool
iw4965_is_ht40_channel(__le32 rxon_flags)
503
{
504 505 506
	int chan_mod =
	    le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK) >>
	    RXON_FLG_CHANNEL_MODE_POS;
507 508
	return (chan_mod == CHANNEL_MODE_PURE_40 ||
		chan_mod == CHANNEL_MODE_MIXED);
509 510
}

511 512
static void
il4965_nic_config(struct il_priv *il)
513 514 515 516
{
	unsigned long flags;
	u16 radio_cfg;

S
Stanislaw Gruszka 已提交
517
	spin_lock_irqsave(&il->lock, flags);
518

S
Stanislaw Gruszka 已提交
519
	radio_cfg = il_eeprom_query16(il, EEPROM_RADIO_CONFIG);
520 521 522

	/* write radio config values to register */
	if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) == EEPROM_4965_RF_CFG_TYPE_MAX)
S
Stanislaw Gruszka 已提交
523
		il_set_bit(il, CSR_HW_IF_CONFIG_REG,
524 525 526
			   EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
			   EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
			   EEPROM_RF_CFG_DASH_MSK(radio_cfg));
527 528

	/* set CSR_HW_CONFIG_REG for uCode use */
S
Stanislaw Gruszka 已提交
529
	il_set_bit(il, CSR_HW_IF_CONFIG_REG,
530 531
		   CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
		   CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
532

533
	il->calib_info =
S
Stanislaw Gruszka 已提交
534 535
	    (struct il_eeprom_calib_info *)
	    il_eeprom_query_addr(il, EEPROM_4965_CALIB_TXPOWER_OFFSET);
536

S
Stanislaw Gruszka 已提交
537
	spin_unlock_irqrestore(&il->lock, flags);
538 539 540 541 542
}

/* Reset differential Rx gains in NIC to prepare for chain noise calibration.
 * Called after every association, but this runs only once!
 *  ... once chain noise is calibrated the first time, it's good forever.  */
543 544
static void
il4965_chain_noise_reset(struct il_priv *il)
545
{
S
Stanislaw Gruszka 已提交
546
	struct il_chain_noise_data *data = &(il->chain_noise_data);
547

548
	if (data->state == IL_CHAIN_NOISE_ALIVE && il_is_any_associated(il)) {
S
Stanislaw Gruszka 已提交
549
		struct il_calib_diff_gain_cmd cmd;
550 551 552 553 554 555 556 557 558 559 560

		/* clear data for chain noise calibration algorithm */
		data->chain_noise_a = 0;
		data->chain_noise_b = 0;
		data->chain_noise_c = 0;
		data->chain_signal_a = 0;
		data->chain_signal_b = 0;
		data->chain_signal_c = 0;
		data->beacon_count = 0;

		memset(&cmd, 0, sizeof(cmd));
S
Stanislaw Gruszka 已提交
561
		cmd.hdr.op_code = IL_PHY_CALIBRATE_DIFF_GAIN_CMD;
562 563 564
		cmd.diff_gain_a = 0;
		cmd.diff_gain_b = 0;
		cmd.diff_gain_c = 0;
565 566
		if (il_send_cmd_pdu(il, C_PHY_CALIBRATION, sizeof(cmd), &cmd))
			IL_ERR("Could not send C_PHY_CALIBRATION\n");
S
Stanislaw Gruszka 已提交
567
		data->state = IL_CHAIN_NOISE_ACCUMULATE;
568
		D_CALIB("Run chain_noise_calibrate\n");
569 570 571
	}
}

572 573
static s32
il4965_math_div_round(s32 num, s32 denom, s32 * res)
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
{
	s32 sign = 1;

	if (num < 0) {
		sign = -sign;
		num = -num;
	}
	if (denom < 0) {
		sign = -sign;
		denom = -denom;
	}
	*res = 1;
	*res = ((num * 2 + denom) / (denom * 2)) * sign;

	return 1;
}

/**
S
Stanislaw Gruszka 已提交
592
 * il4965_get_voltage_compensation - Power supply voltage comp for txpower
593 594
 *
 * Determines power supply voltage compensation for txpower calculations.
S
Stanislaw Gruszka 已提交
595
 * Returns number of 1/2-dB steps to subtract from gain table idx,
596 597 598 599
 * to compensate for difference between power supply voltage during
 * factory measurements, vs. current power supply voltage.
 *
 * Voltage indication is higher for lower voltage.
S
Stanislaw Gruszka 已提交
600
 * Lower voltage requires more gain (lower gain table idx).
601
 */
602 603
static s32
il4965_get_voltage_compensation(s32 eeprom_voltage, s32 current_voltage)
604 605 606
{
	s32 comp = 0;

607 608
	if (TX_POWER_IL_ILLEGAL_VOLTAGE == eeprom_voltage ||
	    TX_POWER_IL_ILLEGAL_VOLTAGE == current_voltage)
609 610
		return 0;

S
Stanislaw Gruszka 已提交
611
	il4965_math_div_round(current_voltage - eeprom_voltage,
612
			      TX_POWER_IL_VOLTAGE_CODES_PER_03V, &comp);
613 614 615 616 617 618 619 620 621

	if (current_voltage > eeprom_voltage)
		comp *= 2;
	if ((comp < -2) || (comp > 2))
		comp = 0;

	return comp;
}

622 623
static s32
il4965_get_tx_atten_grp(u16 channel)
624
{
S
Stanislaw Gruszka 已提交
625 626
	if (channel >= CALIB_IL_TX_ATTEN_GR5_FCH &&
	    channel <= CALIB_IL_TX_ATTEN_GR5_LCH)
627 628
		return CALIB_CH_GROUP_5;

S
Stanislaw Gruszka 已提交
629 630
	if (channel >= CALIB_IL_TX_ATTEN_GR1_FCH &&
	    channel <= CALIB_IL_TX_ATTEN_GR1_LCH)
631 632
		return CALIB_CH_GROUP_1;

S
Stanislaw Gruszka 已提交
633 634
	if (channel >= CALIB_IL_TX_ATTEN_GR2_FCH &&
	    channel <= CALIB_IL_TX_ATTEN_GR2_LCH)
635 636
		return CALIB_CH_GROUP_2;

S
Stanislaw Gruszka 已提交
637 638
	if (channel >= CALIB_IL_TX_ATTEN_GR3_FCH &&
	    channel <= CALIB_IL_TX_ATTEN_GR3_LCH)
639 640
		return CALIB_CH_GROUP_3;

S
Stanislaw Gruszka 已提交
641 642
	if (channel >= CALIB_IL_TX_ATTEN_GR4_FCH &&
	    channel <= CALIB_IL_TX_ATTEN_GR4_LCH)
643 644
		return CALIB_CH_GROUP_4;

645
	return -EINVAL;
646 647
}

648 649
static u32
il4965_get_sub_band(const struct il_priv *il, u32 channel)
650 651 652 653
{
	s32 b = -1;

	for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) {
S
Stanislaw Gruszka 已提交
654
		if (il->calib_info->band_info[b].ch_from == 0)
655 656
			continue;

657 658
		if (channel >= il->calib_info->band_info[b].ch_from &&
		    channel <= il->calib_info->band_info[b].ch_to)
659 660 661 662 663 664
			break;
	}

	return b;
}

665 666
static s32
il4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
667 668 669 670 671 672
{
	s32 val;

	if (x2 == x1)
		return y1;
	else {
S
Stanislaw Gruszka 已提交
673
		il4965_math_div_round((x2 - x) * (y1 - y2), (x2 - x1), &val);
674 675 676 677 678
		return val + y2;
	}
}

/**
S
Stanislaw Gruszka 已提交
679
 * il4965_interpolate_chan - Interpolate factory measurements for one channel
680 681 682 683 684 685
 *
 * Interpolates factory measurements from the two sample channels within a
 * sub-band, to apply to channel of interest.  Interpolation is proportional to
 * differences in channel frequencies, which is proportional to differences
 * in channel number.
 */
686 687 688
static int
il4965_interpolate_chan(struct il_priv *il, u32 channel,
			struct il_eeprom_calib_ch_info *chan_info)
689 690 691 692
{
	s32 s = -1;
	u32 c;
	u32 m;
S
Stanislaw Gruszka 已提交
693 694 695
	const struct il_eeprom_calib_measure *m1;
	const struct il_eeprom_calib_measure *m2;
	struct il_eeprom_calib_measure *omeas;
696 697 698
	u32 ch_i1;
	u32 ch_i2;

S
Stanislaw Gruszka 已提交
699
	s = il4965_get_sub_band(il, channel);
700
	if (s >= EEPROM_TX_POWER_BANDS) {
701
		IL_ERR("Tx Power can not find channel %d\n", channel);
702 703 704
		return -1;
	}

S
Stanislaw Gruszka 已提交
705 706
	ch_i1 = il->calib_info->band_info[s].ch1.ch_num;
	ch_i2 = il->calib_info->band_info[s].ch2.ch_num;
707 708
	chan_info->ch_num = (u8) channel;

709 710
	D_TXPOWER("channel %d subband %d factory cal ch %d & %d\n", channel, s,
		  ch_i1, ch_i2);
711 712 713

	for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) {
		for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) {
S
Stanislaw Gruszka 已提交
714
			m1 = &(il->calib_info->band_info[s].ch1.
715
			       measurements[c][m]);
S
Stanislaw Gruszka 已提交
716
			m2 = &(il->calib_info->band_info[s].ch2.
717 718 719 720
			       measurements[c][m]);
			omeas = &(chan_info->measurements[c][m]);

			omeas->actual_pow =
S
Stanislaw Gruszka 已提交
721
			    (u8) il4965_interpolate_value(channel, ch_i1,
722 723
							  m1->actual_pow, ch_i2,
							  m2->actual_pow);
724
			omeas->gain_idx =
S
Stanislaw Gruszka 已提交
725
			    (u8) il4965_interpolate_value(channel, ch_i1,
726 727
							  m1->gain_idx, ch_i2,
							  m2->gain_idx);
728
			omeas->temperature =
S
Stanislaw Gruszka 已提交
729
			    (u8) il4965_interpolate_value(channel, ch_i1,
730 731 732
							  m1->temperature,
							  ch_i2,
							  m2->temperature);
733
			omeas->pa_det =
S
Stanislaw Gruszka 已提交
734
			    (s8) il4965_interpolate_value(channel, ch_i1,
735 736 737 738 739 740 741 742 743 744 745 746 747 748
							  m1->pa_det, ch_i2,
							  m2->pa_det);

			D_TXPOWER("chain %d meas %d AP1=%d AP2=%d AP=%d\n", c,
				  m, m1->actual_pow, m2->actual_pow,
				  omeas->actual_pow);
			D_TXPOWER("chain %d meas %d NI1=%d NI2=%d NI=%d\n", c,
				  m, m1->gain_idx, m2->gain_idx,
				  omeas->gain_idx);
			D_TXPOWER("chain %d meas %d PA1=%d PA2=%d PA=%d\n", c,
				  m, m1->pa_det, m2->pa_det, omeas->pa_det);
			D_TXPOWER("chain %d meas %d  T1=%d  T2=%d  T=%d\n", c,
				  m, m1->temperature, m2->temperature,
				  omeas->temperature);
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
		}
	}

	return 0;
}

/* bit-rate-dependent table to prevent Tx distortion, in half-dB units,
 * for OFDM 6, 12, 18, 24, 36, 48, 54, 60 MBit, and CCK all rates. */
static s32 back_off_table[] = {
	10, 10, 10, 10, 10, 15, 17, 20,	/* OFDM SISO 20 MHz */
	10, 10, 10, 10, 10, 15, 17, 20,	/* OFDM MIMO 20 MHz */
	10, 10, 10, 10, 10, 15, 17, 20,	/* OFDM SISO 40 MHz */
	10, 10, 10, 10, 10, 15, 17, 20,	/* OFDM MIMO 40 MHz */
	10			/* CCK */
};

/* Thermal compensation values for txpower for various frequency ranges ...
 *   ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust */
S
Stanislaw Gruszka 已提交
767
static struct il4965_txpower_comp_entry {
768 769 770
	s32 degrees_per_05db_a;
	s32 degrees_per_05db_a_denom;
} tx_power_cmp_tble[CALIB_CH_GROUP_MAX] = {
771 772 773 774 775 776 777 778 779 780
	{
	9, 2},			/* group 0 5.2, ch  34-43 */
	{
	4, 1},			/* group 1 5.2, ch  44-70 */
	{
	4, 1},			/* group 2 5.2, ch  71-124 */
	{
	4, 1},			/* group 3 5.2, ch 125-200 */
	{
	3, 1}			/* group 4 2.4, ch   all */
781 782
};

783 784
static s32
get_min_power_idx(s32 rate_power_idx, u32 band)
785 786
{
	if (!band) {
S
Stanislaw Gruszka 已提交
787
		if ((rate_power_idx & 7) <= 4)
S
Stanislaw Gruszka 已提交
788
			return MIN_TX_GAIN_IDX_52GHZ_EXT;
789
	}
S
Stanislaw Gruszka 已提交
790
	return MIN_TX_GAIN_IDX;
791 792 793 794 795 796 797 798
}

struct gain_entry {
	u8 dsp;
	u8 radio;
};

static const struct gain_entry gain_table[2][108] = {
S
Stanislaw Gruszka 已提交
799
	/* 5.2GHz power gain idx table */
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
	{
	 {123, 0x3F},		/* highest txpower */
	 {117, 0x3F},
	 {110, 0x3F},
	 {104, 0x3F},
	 {98, 0x3F},
	 {110, 0x3E},
	 {104, 0x3E},
	 {98, 0x3E},
	 {110, 0x3D},
	 {104, 0x3D},
	 {98, 0x3D},
	 {110, 0x3C},
	 {104, 0x3C},
	 {98, 0x3C},
	 {110, 0x3B},
	 {104, 0x3B},
	 {98, 0x3B},
	 {110, 0x3A},
	 {104, 0x3A},
	 {98, 0x3A},
	 {110, 0x39},
	 {104, 0x39},
	 {98, 0x39},
	 {110, 0x38},
	 {104, 0x38},
	 {98, 0x38},
	 {110, 0x37},
	 {104, 0x37},
	 {98, 0x37},
	 {110, 0x36},
	 {104, 0x36},
	 {98, 0x36},
	 {110, 0x35},
	 {104, 0x35},
	 {98, 0x35},
	 {110, 0x34},
	 {104, 0x34},
	 {98, 0x34},
	 {110, 0x33},
	 {104, 0x33},
	 {98, 0x33},
	 {110, 0x32},
	 {104, 0x32},
	 {98, 0x32},
	 {110, 0x31},
	 {104, 0x31},
	 {98, 0x31},
	 {110, 0x30},
	 {104, 0x30},
	 {98, 0x30},
	 {110, 0x25},
	 {104, 0x25},
	 {98, 0x25},
	 {110, 0x24},
	 {104, 0x24},
	 {98, 0x24},
	 {110, 0x23},
	 {104, 0x23},
	 {98, 0x23},
	 {110, 0x22},
	 {104, 0x18},
	 {98, 0x18},
	 {110, 0x17},
	 {104, 0x17},
	 {98, 0x17},
	 {110, 0x16},
	 {104, 0x16},
	 {98, 0x16},
	 {110, 0x15},
	 {104, 0x15},
	 {98, 0x15},
	 {110, 0x14},
	 {104, 0x14},
	 {98, 0x14},
	 {110, 0x13},
	 {104, 0x13},
	 {98, 0x13},
	 {110, 0x12},
	 {104, 0x08},
	 {98, 0x08},
	 {110, 0x07},
	 {104, 0x07},
	 {98, 0x07},
	 {110, 0x06},
	 {104, 0x06},
	 {98, 0x06},
	 {110, 0x05},
	 {104, 0x05},
	 {98, 0x05},
	 {110, 0x04},
	 {104, 0x04},
	 {98, 0x04},
	 {110, 0x03},
	 {104, 0x03},
	 {98, 0x03},
	 {110, 0x02},
	 {104, 0x02},
	 {98, 0x02},
	 {110, 0x01},
	 {104, 0x01},
	 {98, 0x01},
	 {110, 0x00},
	 {104, 0x00},
	 {98, 0x00},
	 {93, 0x00},
	 {88, 0x00},
	 {83, 0x00},
	 {78, 0x00},
	 },
S
Stanislaw Gruszka 已提交
910
	/* 2.4GHz power gain idx table */
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
	{
	 {110, 0x3f},		/* highest txpower */
	 {104, 0x3f},
	 {98, 0x3f},
	 {110, 0x3e},
	 {104, 0x3e},
	 {98, 0x3e},
	 {110, 0x3d},
	 {104, 0x3d},
	 {98, 0x3d},
	 {110, 0x3c},
	 {104, 0x3c},
	 {98, 0x3c},
	 {110, 0x3b},
	 {104, 0x3b},
	 {98, 0x3b},
	 {110, 0x3a},
	 {104, 0x3a},
	 {98, 0x3a},
	 {110, 0x39},
	 {104, 0x39},
	 {98, 0x39},
	 {110, 0x38},
	 {104, 0x38},
	 {98, 0x38},
	 {110, 0x37},
	 {104, 0x37},
	 {98, 0x37},
	 {110, 0x36},
	 {104, 0x36},
	 {98, 0x36},
	 {110, 0x35},
	 {104, 0x35},
	 {98, 0x35},
	 {110, 0x34},
	 {104, 0x34},
	 {98, 0x34},
	 {110, 0x33},
	 {104, 0x33},
	 {98, 0x33},
	 {110, 0x32},
	 {104, 0x32},
	 {98, 0x32},
	 {110, 0x31},
	 {104, 0x31},
	 {98, 0x31},
	 {110, 0x30},
	 {104, 0x30},
	 {98, 0x30},
	 {110, 0x6},
	 {104, 0x6},
	 {98, 0x6},
	 {110, 0x5},
	 {104, 0x5},
	 {98, 0x5},
	 {110, 0x4},
	 {104, 0x4},
	 {98, 0x4},
	 {110, 0x3},
	 {104, 0x3},
	 {98, 0x3},
	 {110, 0x2},
	 {104, 0x2},
	 {98, 0x2},
	 {110, 0x1},
	 {104, 0x1},
	 {98, 0x1},
	 {110, 0x0},
	 {104, 0x0},
	 {98, 0x0},
	 {97, 0},
	 {96, 0},
	 {95, 0},
	 {94, 0},
	 {93, 0},
	 {92, 0},
	 {91, 0},
	 {90, 0},
	 {89, 0},
	 {88, 0},
	 {87, 0},
	 {86, 0},
	 {85, 0},
	 {84, 0},
	 {83, 0},
	 {82, 0},
	 {81, 0},
	 {80, 0},
	 {79, 0},
	 {78, 0},
	 {77, 0},
	 {76, 0},
	 {75, 0},
	 {74, 0},
	 {73, 0},
	 {72, 0},
	 {71, 0},
	 {70, 0},
	 {69, 0},
	 {68, 0},
	 {67, 0},
	 {66, 0},
	 {65, 0},
	 {64, 0},
	 {63, 0},
	 {62, 0},
	 {61, 0},
	 {60, 0},
	 {59, 0},
	 }
};

1023 1024 1025 1026
static int
il4965_fill_txpower_tbl(struct il_priv *il, u8 band, u16 channel, u8 is_ht40,
			u8 ctrl_chan_high,
			struct il4965_tx_power_db *tx_power_tbl)
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
{
	u8 saturation_power;
	s32 target_power;
	s32 user_target_power;
	s32 power_limit;
	s32 current_temp;
	s32 reg_limit;
	s32 current_regulatory;
	s32 txatten_grp = CALIB_CH_GROUP_MAX;
	int i;
	int c;
S
Stanislaw Gruszka 已提交
1038 1039 1040
	const struct il_channel_info *ch_info = NULL;
	struct il_eeprom_calib_ch_info ch_eeprom_info;
	const struct il_eeprom_calib_measure *measurement;
1041 1042 1043 1044 1045 1046 1047
	s16 voltage;
	s32 init_voltage;
	s32 voltage_compensation;
	s32 degrees_per_05db_num;
	s32 degrees_per_05db_denom;
	s32 factory_temp;
	s32 temperature_comp[2];
S
Stanislaw Gruszka 已提交
1048
	s32 factory_gain_idx[2];
1049
	s32 factory_actual_pwr[2];
S
Stanislaw Gruszka 已提交
1050
	s32 power_idx;
1051 1052

	/* tx_power_user_lmt is in dBm, convert to half-dBm (half-dB units
S
Stanislaw Gruszka 已提交
1053
	 *   are used for idxing into txpower table) */
S
Stanislaw Gruszka 已提交
1054
	user_target_power = 2 * il->tx_power_user_lmt;
1055 1056

	/* Get current (RXON) channel, band, width */
1057
	D_TXPOWER("chan %d band %d is_ht40 %d\n", channel, band, is_ht40);
1058

S
Stanislaw Gruszka 已提交
1059
	ch_info = il_get_channel_info(il, il->band, channel);
1060

S
Stanislaw Gruszka 已提交
1061
	if (!il_is_channel_valid(ch_info))
1062 1063 1064 1065
		return -EINVAL;

	/* get txatten group, used to select 1) thermal txpower adjustment
	 *   and 2) mimo txpower balance between Tx chains. */
S
Stanislaw Gruszka 已提交
1066
	txatten_grp = il4965_get_tx_atten_grp(channel);
1067
	if (txatten_grp < 0) {
1068
		IL_ERR("Can't find txatten group for channel %d.\n", channel);
1069
		return txatten_grp;
1070 1071
	}

1072 1073
	D_TXPOWER("channel %d belongs to txatten group %d\n", channel,
		  txatten_grp);
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084

	if (is_ht40) {
		if (ctrl_chan_high)
			channel -= 2;
		else
			channel += 2;
	}

	/* hardware txpower limits ...
	 * saturation (clipping distortion) txpowers are in half-dBm */
	if (band)
S
Stanislaw Gruszka 已提交
1085
		saturation_power = il->calib_info->saturation_power24;
1086
	else
S
Stanislaw Gruszka 已提交
1087
		saturation_power = il->calib_info->saturation_power52;
1088

S
Stanislaw Gruszka 已提交
1089 1090
	if (saturation_power < IL_TX_POWER_SATURATION_MIN ||
	    saturation_power > IL_TX_POWER_SATURATION_MAX) {
1091
		if (band)
S
Stanislaw Gruszka 已提交
1092
			saturation_power = IL_TX_POWER_DEFAULT_SATURATION_24;
1093
		else
S
Stanislaw Gruszka 已提交
1094
			saturation_power = IL_TX_POWER_DEFAULT_SATURATION_52;
1095 1096 1097 1098 1099 1100 1101 1102 1103
	}

	/* regulatory txpower limits ... reg_limit values are in half-dBm,
	 *   max_power_avg values are in dBm, convert * 2 */
	if (is_ht40)
		reg_limit = ch_info->ht40_max_power_avg * 2;
	else
		reg_limit = ch_info->max_power_avg * 2;

S
Stanislaw Gruszka 已提交
1104 1105
	if ((reg_limit < IL_TX_POWER_REGULATORY_MIN) ||
	    (reg_limit > IL_TX_POWER_REGULATORY_MAX)) {
1106
		if (band)
S
Stanislaw Gruszka 已提交
1107
			reg_limit = IL_TX_POWER_DEFAULT_REGULATORY_24;
1108
		else
S
Stanislaw Gruszka 已提交
1109
			reg_limit = IL_TX_POWER_DEFAULT_REGULATORY_52;
1110 1111 1112 1113
	}

	/* Interpolate txpower calibration values for this channel,
	 *   based on factory calibration tests on spaced channels. */
S
Stanislaw Gruszka 已提交
1114
	il4965_interpolate_chan(il, channel, &ch_eeprom_info);
1115 1116

	/* calculate tx gain adjustment based on power supply voltage */
S
Stanislaw Gruszka 已提交
1117
	voltage = le16_to_cpu(il->calib_info->voltage);
1118
	init_voltage = (s32) le32_to_cpu(il->card_alive_init.voltage);
1119
	voltage_compensation =
S
Stanislaw Gruszka 已提交
1120
	    il4965_get_voltage_compensation(voltage, init_voltage);
1121

1122 1123
	D_TXPOWER("curr volt %d eeprom volt %d volt comp %d\n", init_voltage,
		  voltage, voltage_compensation);
1124 1125

	/* get current temperature (Celsius) */
S
Stanislaw Gruszka 已提交
1126 1127
	current_temp = max(il->temperature, IL_TX_POWER_TEMPERATURE_MIN);
	current_temp = min(il->temperature, IL_TX_POWER_TEMPERATURE_MAX);
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
	current_temp = KELVIN_TO_CELSIUS(current_temp);

	/* select thermal txpower adjustment params, based on channel group
	 *   (same frequency group used for mimo txatten adjustment) */
	degrees_per_05db_num =
	    tx_power_cmp_tble[txatten_grp].degrees_per_05db_a;
	degrees_per_05db_denom =
	    tx_power_cmp_tble[txatten_grp].degrees_per_05db_a_denom;

	/* get per-chain txpower values from factory measurements */
	for (c = 0; c < 2; c++) {
		measurement = &ch_eeprom_info.measurements[c][1];

		/* txgain adjustment (in half-dB steps) based on difference
		 *   between factory and current temperature */
		factory_temp = measurement->temperature;
1144 1145 1146 1147
		il4965_math_div_round((current_temp -
				       factory_temp) * degrees_per_05db_denom,
				      degrees_per_05db_num,
				      &temperature_comp[c]);
1148

S
Stanislaw Gruszka 已提交
1149
		factory_gain_idx[c] = measurement->gain_idx;
1150 1151
		factory_actual_pwr[c] = measurement->actual_pow;

1152
		D_TXPOWER("chain = %d\n", c);
1153 1154 1155 1156 1157
		D_TXPOWER("fctry tmp %d, " "curr tmp %d, comp %d steps\n",
			  factory_temp, current_temp, temperature_comp[c]);

		D_TXPOWER("fctry idx %d, fctry pwr %d\n", factory_gain_idx[c],
			  factory_actual_pwr[c]);
1158 1159 1160
	}

	/* for each of 33 bit-rates (including 1 for CCK) */
S
Stanislaw Gruszka 已提交
1161
	for (i = 0; i < POWER_TBL_NUM_ENTRIES; i++) {
1162
		u8 is_mimo_rate;
S
Stanislaw Gruszka 已提交
1163
		union il4965_tx_power_dual_stream tx_power;
1164 1165 1166 1167 1168

		/* for mimo, reduce each chain's txpower by half
		 * (3dB, 6 steps), so total output power is regulatory
		 * compliant. */
		if (i & 0x8) {
1169 1170
			current_regulatory =
			    reg_limit -
S
Stanislaw Gruszka 已提交
1171
			    IL_TX_POWER_MIMO_REGULATORY_COMPENSATION;
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
			is_mimo_rate = 1;
		} else {
			current_regulatory = reg_limit;
			is_mimo_rate = 0;
		}

		/* find txpower limit, either hardware or regulatory */
		power_limit = saturation_power - back_off_table[i];
		if (power_limit > current_regulatory)
			power_limit = current_regulatory;

		/* reduce user's txpower request if necessary
		 * for this rate on this channel */
		target_power = user_target_power;
		if (target_power > power_limit)
			target_power = power_limit;

1189 1190 1191
		D_TXPOWER("rate %d sat %d reg %d usr %d tgt %d\n", i,
			  saturation_power - back_off_table[i],
			  current_regulatory, user_target_power, target_power);
1192 1193 1194 1195 1196 1197 1198

		/* for each of 2 Tx chains (radio transmitters) */
		for (c = 0; c < 2; c++) {
			s32 atten_value;

			if (is_mimo_rate)
				atten_value =
1199 1200
				    (s32) le32_to_cpu(il->card_alive_init.
						      tx_atten[txatten_grp][c]);
1201 1202 1203
			else
				atten_value = 0;

S
Stanislaw Gruszka 已提交
1204
			/* calculate idx; higher idx means lower txpower */
1205 1206 1207 1208 1209
			power_idx =
			    (u8) (factory_gain_idx[c] -
				  (target_power - factory_actual_pwr[c]) -
				  temperature_comp[c] - voltage_compensation +
				  atten_value);
1210

S
Stanislaw Gruszka 已提交
1211 1212
/*			D_TXPOWER("calculated txpower idx %d\n",
						power_idx); */
1213

S
Stanislaw Gruszka 已提交
1214 1215
			if (power_idx < get_min_power_idx(i, band))
				power_idx = get_min_power_idx(i, band);
1216

S
Stanislaw Gruszka 已提交
1217
			/* adjust 5 GHz idx to support negative idxes */
1218
			if (!band)
S
Stanislaw Gruszka 已提交
1219
				power_idx += 9;
1220 1221

			/* CCK, rate 32, reduce txpower for CCK */
S
Stanislaw Gruszka 已提交
1222
			if (i == POWER_TBL_CCK_ENTRY)
S
Stanislaw Gruszka 已提交
1223
				power_idx +=
S
Stanislaw Gruszka 已提交
1224
				    IL_TX_POWER_CCK_COMPENSATION_C_STEP;
1225 1226

			/* stay within the table! */
S
Stanislaw Gruszka 已提交
1227
			if (power_idx > 107) {
1228
				IL_WARN("txpower idx %d > 107\n", power_idx);
S
Stanislaw Gruszka 已提交
1229
				power_idx = 107;
1230
			}
S
Stanislaw Gruszka 已提交
1231
			if (power_idx < 0) {
1232
				IL_WARN("txpower idx %d < 0\n", power_idx);
S
Stanislaw Gruszka 已提交
1233
				power_idx = 0;
1234 1235 1236 1237
			}

			/* fill txpower command for this rate/chain */
			tx_power.s.radio_tx_gain[c] =
1238
			    gain_table[band][power_idx].radio;
1239
			tx_power.s.dsp_predis_atten[c] =
1240
			    gain_table[band][power_idx].dsp;
1241

S
Stanislaw Gruszka 已提交
1242
			D_TXPOWER("chain %d mimo %d idx %d "
1243 1244 1245 1246
				  "gain 0x%02x dsp %d\n", c, atten_value,
				  power_idx, tx_power.s.radio_tx_gain[c],
				  tx_power.s.dsp_predis_atten[c]);
		}		/* for each chain */
1247 1248 1249

		tx_power_tbl->power_tbl[i].dw = cpu_to_le32(tx_power.dw);

1250
	}			/* for each rate */
1251 1252 1253 1254 1255

	return 0;
}

/**
S
Stanislaw Gruszka 已提交
1256
 * il4965_send_tx_power - Configure the TXPOWER level user limit
1257 1258
 *
 * Uses the active RXON for channel, band, and characteristics (ht40, high)
S
Stanislaw Gruszka 已提交
1259
 * The power limit is taken from il->tx_power_user_lmt.
1260
 */
1261 1262
static int
il4965_send_tx_power(struct il_priv *il)
1263
{
S
Stanislaw Gruszka 已提交
1264
	struct il4965_txpowertable_cmd cmd = { 0 };
1265 1266 1267 1268 1269
	int ret;
	u8 band = 0;
	bool is_ht40 = false;
	u8 ctrl_chan_high = 0;

1270 1271 1272
	if (WARN_ONCE
	    (test_bit(S_SCAN_HW, &il->status),
	     "TX Power requested while scanning!\n"))
1273 1274
		return -EAGAIN;

S
Stanislaw Gruszka 已提交
1275
	band = il->band == IEEE80211_BAND_2GHZ;
1276

1277
	is_ht40 = iw4965_is_ht40_channel(il->active.flags);
1278

1279
	if (is_ht40 && (il->active.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
1280 1281 1282
		ctrl_chan_high = 1;

	cmd.band = band;
1283
	cmd.channel = il->active.channel;
1284

1285
	ret =
1286
	    il4965_fill_txpower_tbl(il, band, le16_to_cpu(il->active.channel),
1287
				    is_ht40, ctrl_chan_high, &cmd.tx_power);
1288 1289 1290
	if (ret)
		goto out;

1291
	ret = il_send_cmd_pdu(il, C_TX_PWR_TBL, sizeof(cmd), &cmd);
1292 1293 1294 1295 1296

out:
	return ret;
}

1297
static int
1298
il4965_send_rxon_assoc(struct il_priv *il)
1299 1300
{
	int ret = 0;
S
Stanislaw Gruszka 已提交
1301
	struct il4965_rxon_assoc_cmd rxon_assoc;
1302 1303
	const struct il_rxon_cmd *rxon1 = &il->staging;
	const struct il_rxon_cmd *rxon2 = &il->active;
1304

1305 1306 1307 1308
	if (rxon1->flags == rxon2->flags &&
	    rxon1->filter_flags == rxon2->filter_flags &&
	    rxon1->cck_basic_rates == rxon2->cck_basic_rates &&
	    rxon1->ofdm_ht_single_stream_basic_rates ==
1309
	    rxon2->ofdm_ht_single_stream_basic_rates &&
1310
	    rxon1->ofdm_ht_dual_stream_basic_rates ==
1311
	    rxon2->ofdm_ht_dual_stream_basic_rates &&
1312 1313
	    rxon1->rx_chain == rxon2->rx_chain &&
	    rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates) {
1314
		D_INFO("Using current RXON_ASSOC.  Not resending.\n");
1315 1316 1317
		return 0;
	}

1318 1319 1320 1321
	rxon_assoc.flags = il->staging.flags;
	rxon_assoc.filter_flags = il->staging.filter_flags;
	rxon_assoc.ofdm_basic_rates = il->staging.ofdm_basic_rates;
	rxon_assoc.cck_basic_rates = il->staging.cck_basic_rates;
1322 1323
	rxon_assoc.reserved = 0;
	rxon_assoc.ofdm_ht_single_stream_basic_rates =
1324
	    il->staging.ofdm_ht_single_stream_basic_rates;
1325
	rxon_assoc.ofdm_ht_dual_stream_basic_rates =
1326 1327
	    il->staging.ofdm_ht_dual_stream_basic_rates;
	rxon_assoc.rx_chain_select_flags = il->staging.rx_chain;
1328

1329 1330 1331
	ret =
	    il_send_cmd_pdu_async(il, C_RXON_ASSOC, sizeof(rxon_assoc),
				  &rxon_assoc, NULL);
1332 1333 1334 1335

	return ret;
}

1336
static int
1337
il4965_commit_rxon(struct il_priv *il)
1338 1339
{
	/* cast away the const for active_rxon in this function */
1340
	struct il_rxon_cmd *active_rxon = (void *)&il->active;
1341
	int ret;
1342
	bool new_assoc = !!(il->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
1343

S
Stanislaw Gruszka 已提交
1344
	if (!il_is_alive(il))
1345 1346 1347
		return -EBUSY;

	/* always get timestamp with Rx frame */
1348
	il->staging.flags |= RXON_FLG_TSF2HOST_MSK;
1349

1350
	ret = il_check_rxon_cmd(il);
1351
	if (ret) {
1352
		IL_ERR("Invalid RXON configuration.  Not committing.\n");
1353 1354 1355 1356 1357 1358 1359
		return -EINVAL;
	}

	/*
	 * receive commit_rxon request
	 * abort any previous channel switch if still in process
	 */
S
Stanislaw Gruszka 已提交
1360
	if (test_bit(S_CHANNEL_SWITCH_PENDING, &il->status) &&
1361
	    il->switch_channel != il->staging.channel) {
1362
		D_11H("abort channel switch on %d\n",
S
Stanislaw Gruszka 已提交
1363 1364
		      le16_to_cpu(il->switch_channel));
		il_chswitch_done(il, false);
1365 1366 1367
	}

	/* If we don't need to send a full RXON, we can use
S
Stanislaw Gruszka 已提交
1368
	 * il_rxon_assoc_cmd which is used to reconfigure filter
1369
	 * and other flags for the current radio configuration. */
1370 1371
	if (!il_full_rxon_required(il)) {
		ret = il_send_rxon_assoc(il);
1372
		if (ret) {
1373
			IL_ERR("Error setting RXON_ASSOC (%d)\n", ret);
1374 1375 1376
			return ret;
		}

1377
		memcpy(active_rxon, &il->staging, sizeof(*active_rxon));
1378
		il_print_rx_config_cmd(il);
1379 1380 1381 1382
		/*
		 * We do not commit tx power settings while channel changing,
		 * do it now if tx power changed.
		 */
S
Stanislaw Gruszka 已提交
1383
		il_set_tx_power(il, il->tx_power_next, false);
1384
		return 0;
1385 1386 1387 1388 1389 1390
	}

	/* 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 */
1391
	if (il_is_associated(il) && new_assoc) {
1392
		D_INFO("Toggling associated bit on current RXON\n");
1393 1394
		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;

1395
		ret =
1396
		    il_send_cmd_pdu(il, C_RXON,
1397
				    sizeof(struct il_rxon_cmd), active_rxon);
1398 1399 1400 1401 1402

		/* If the mask clearing failed then we set
		 * active_rxon back to what it was previously */
		if (ret) {
			active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
1403
			IL_ERR("Error clearing ASSOC_MSK (%d)\n", ret);
1404 1405
			return ret;
		}
1406 1407 1408
		il_clear_ucode_stations(il);
		il_restore_stations(il);
		ret = il4965_restore_default_wep_keys(il);
1409
		if (ret) {
1410
			IL_ERR("Failed to restore WEP keys (%d)\n", ret);
1411 1412 1413 1414
			return ret;
		}
	}

1415 1416
	D_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n"
	       "* channel = %d\n" "* bssid = %pM\n", (new_assoc ? "" : "out"),
1417
	       le16_to_cpu(il->staging.channel), il->staging.bssid_addr);
1418

1419
	il_set_rxon_hwcrypto(il, !il->cfg->mod_params->sw_crypto);
1420 1421 1422 1423 1424 1425

	/* Apply the new configuration
	 * RXON unassoc clears the station table in uCode so restoration of
	 * stations is needed after it (the RXON command) completes
	 */
	if (!new_assoc) {
1426
		ret =
1427
		    il_send_cmd_pdu(il, C_RXON,
1428
				    sizeof(struct il_rxon_cmd), &il->staging);
1429
		if (ret) {
1430
			IL_ERR("Error setting new RXON (%d)\n", ret);
1431 1432
			return ret;
		}
1433
		D_INFO("Return from !new_assoc RXON.\n");
1434
		memcpy(active_rxon, &il->staging, sizeof(*active_rxon));
1435 1436 1437
		il_clear_ucode_stations(il);
		il_restore_stations(il);
		ret = il4965_restore_default_wep_keys(il);
1438
		if (ret) {
1439
			IL_ERR("Failed to restore WEP keys (%d)\n", ret);
1440 1441 1442 1443
			return ret;
		}
	}
	if (new_assoc) {
S
Stanislaw Gruszka 已提交
1444
		il->start_calib = 0;
1445 1446 1447
		/* Apply the new configuration
		 * RXON assoc doesn't clear the station table in uCode,
		 */
1448
		ret =
1449
		    il_send_cmd_pdu(il, C_RXON,
1450
				    sizeof(struct il_rxon_cmd), &il->staging);
1451
		if (ret) {
1452
			IL_ERR("Error setting new RXON (%d)\n", ret);
1453 1454
			return ret;
		}
1455
		memcpy(active_rxon, &il->staging, sizeof(*active_rxon));
1456
	}
1457
	il_print_rx_config_cmd(il);
1458

S
Stanislaw Gruszka 已提交
1459
	il4965_init_sensitivity(il);
1460 1461 1462

	/* 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 已提交
1463
	ret = il_set_tx_power(il, il->tx_power_next, true);
1464
	if (ret) {
1465
		IL_ERR("Error sending TX power (%d)\n", ret);
1466 1467 1468 1469 1470 1471
		return ret;
	}

	return 0;
}

1472 1473 1474
static int
il4965_hw_channel_switch(struct il_priv *il,
			 struct ieee80211_channel_switch *ch_switch)
1475 1476 1477 1478 1479
{
	int rc;
	u8 band = 0;
	bool is_ht40 = false;
	u8 ctrl_chan_high = 0;
S
Stanislaw Gruszka 已提交
1480 1481
	struct il4965_channel_switch_cmd cmd;
	const struct il_channel_info *ch_info;
1482 1483 1484 1485
	u32 switch_time_in_usec, ucode_switch_time;
	u16 ch;
	u32 tsf_low;
	u8 switch_count;
1486
	u16 beacon_interval = le16_to_cpu(il->timing.beacon_interval);
1487 1488 1489 1490 1491
	struct ieee80211_vif *vif = il->vif;
	band = (il->band == IEEE80211_BAND_2GHZ);

	if (WARN_ON_ONCE(vif == NULL))
		return -EIO;
1492

1493
	is_ht40 = iw4965_is_ht40_channel(il->staging.flags);
1494

1495
	if (is_ht40 && (il->staging.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
1496 1497 1498 1499 1500 1501
		ctrl_chan_high = 1;

	cmd.band = band;
	cmd.expect_beacon = 0;
	ch = ch_switch->channel->hw_value;
	cmd.channel = cpu_to_le16(ch);
1502 1503
	cmd.rxon_flags = il->staging.flags;
	cmd.rxon_filter_flags = il->staging.filter_flags;
1504 1505 1506 1507 1508 1509
	switch_count = ch_switch->count;
	tsf_low = ch_switch->timestamp & 0x0ffffffff;
	/*
	 * calculate the ucode channel switch time
	 * adding TSF as one of the factor for when to switch
	 */
1510
	if (il->ucode_beacon_time > tsf_low && beacon_interval) {
1511 1512 1513 1514
		if (switch_count >
		    ((il->ucode_beacon_time - tsf_low) / beacon_interval)) {
			switch_count -=
			    (il->ucode_beacon_time - tsf_low) / beacon_interval;
1515 1516 1517 1518
		} else
			switch_count = 0;
	}
	if (switch_count <= 1)
S
Stanislaw Gruszka 已提交
1519
		cmd.switch_time = cpu_to_le32(il->ucode_beacon_time);
1520 1521
	else {
		switch_time_in_usec =
1522 1523 1524 1525 1526 1527 1528
		    vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
		ucode_switch_time =
		    il_usecs_to_beacons(il, switch_time_in_usec,
					beacon_interval);
		cmd.switch_time =
		    il_add_beacon_time(il, il->ucode_beacon_time,
				       ucode_switch_time, beacon_interval);
1529
	}
1530
	D_11H("uCode time for the switch is 0x%x\n", cmd.switch_time);
S
Stanislaw Gruszka 已提交
1531
	ch_info = il_get_channel_info(il, il->band, ch);
1532
	if (ch_info)
S
Stanislaw Gruszka 已提交
1533
		cmd.expect_beacon = il_is_channel_radar(ch_info);
1534
	else {
1535
		IL_ERR("invalid channel switch from %u to %u\n",
1536
		       il->active.channel, ch);
1537 1538 1539
		return -EFAULT;
	}

1540 1541
	rc = il4965_fill_txpower_tbl(il, band, ch, is_ht40, ctrl_chan_high,
				     &cmd.tx_power);
1542
	if (rc) {
1543
		D_11H("error:%d  fill txpower_tbl\n", rc);
1544 1545 1546
		return rc;
	}

1547
	return il_send_cmd_pdu(il, C_CHANNEL_SWITCH, sizeof(cmd), &cmd);
1548 1549 1550
}

/**
S
Stanislaw Gruszka 已提交
1551
 * il4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
1552
 */
1553 1554 1555
static void
il4965_txq_update_byte_cnt_tbl(struct il_priv *il, struct il_tx_queue *txq,
			       u16 byte_cnt)
1556
{
S
Stanislaw Gruszka 已提交
1557
	struct il4965_scd_bc_tbl *scd_bc_tbl = il->scd_bc_tbls.addr;
1558 1559
	int txq_id = txq->q.id;
	int write_ptr = txq->q.write_ptr;
S
Stanislaw Gruszka 已提交
1560
	int len = byte_cnt + IL_TX_CRC_SIZE + IL_TX_DELIMITER_SIZE;
1561 1562 1563 1564 1565 1566 1567 1568 1569 1570
	__le16 bc_ent;

	WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);

	bc_ent = cpu_to_le16(len & 0xFFF);
	/* Set up byte count within first 256 entries */
	scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;

	/* If within first 64 entries, duplicate at end */
	if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
1571 1572
		scd_bc_tbl[txq_id].tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] =
		    bc_ent;
1573 1574 1575
}

/**
S
Stanislaw Gruszka 已提交
1576
 * il4965_hw_get_temperature - return the calibrated temperature (in Kelvin)
S
Stanislaw Gruszka 已提交
1577
 * @stats: Provides the temperature reading from the uCode
1578
 *
S
Stanislaw Gruszka 已提交
1579
 * A return of <0 indicates bogus data in the stats
1580
 */
1581 1582
static int
il4965_hw_get_temperature(struct il_priv *il)
1583 1584 1585 1586 1587 1588
{
	s32 temperature;
	s32 vt;
	s32 R1, R2, R3;
	u32 R4;

S
Stanislaw Gruszka 已提交
1589
	if (test_bit(S_TEMPERATURE, &il->status) &&
1590
	    (il->_4965.stats.flag & STATS_REPLY_FLG_HT40_MODE_MSK)) {
1591
		D_TEMP("Running HT40 temperature calibration\n");
1592 1593 1594
		R1 = (s32) le32_to_cpu(il->card_alive_init.therm_r1[1]);
		R2 = (s32) le32_to_cpu(il->card_alive_init.therm_r2[1]);
		R3 = (s32) le32_to_cpu(il->card_alive_init.therm_r3[1]);
S
Stanislaw Gruszka 已提交
1595
		R4 = le32_to_cpu(il->card_alive_init.therm_r4[1]);
1596
	} else {
1597
		D_TEMP("Running temperature calibration\n");
1598 1599 1600
		R1 = (s32) le32_to_cpu(il->card_alive_init.therm_r1[0]);
		R2 = (s32) le32_to_cpu(il->card_alive_init.therm_r2[0]);
		R3 = (s32) le32_to_cpu(il->card_alive_init.therm_r3[0]);
S
Stanislaw Gruszka 已提交
1601
		R4 = le32_to_cpu(il->card_alive_init.therm_r4[0]);
1602 1603 1604 1605 1606
	}

	/*
	 * Temperature is only 23 bits, so sign extend out to 32.
	 *
S
Stanislaw Gruszka 已提交
1607
	 * NOTE If we haven't received a stats notification yet
1608 1609 1610
	 * with an updated temperature, use R4 provided to us in the
	 * "initialize" ALIVE response.
	 */
S
Stanislaw Gruszka 已提交
1611
	if (!test_bit(S_TEMPERATURE, &il->status))
1612 1613
		vt = sign_extend32(R4, 23);
	else
1614 1615 1616
		vt = sign_extend32(le32_to_cpu
				   (il->_4965.stats.general.common.temperature),
				   23);
1617

1618
	D_TEMP("Calib values R[1-3]: %d %d %d R4: %d\n", R1, R2, R3, vt);
1619 1620

	if (R3 == R1) {
1621
		IL_ERR("Calibration conflict R1 == R3\n");
1622 1623 1624 1625 1626 1627 1628
		return -1;
	}

	/* Calculate temperature in degrees Kelvin, adjust by 97%.
	 * Add offset to center the adjustment around 0 degrees Centigrade. */
	temperature = TEMPERATURE_CALIB_A_VAL * (vt - R2);
	temperature /= (R3 - R1);
1629 1630
	temperature =
	    (temperature * 97) / 100 + TEMPERATURE_CALIB_KELVIN_OFFSET;
1631

1632 1633
	D_TEMP("Calibrated temperature: %dK, %dC\n", temperature,
	       KELVIN_TO_CELSIUS(temperature));
1634 1635 1636 1637 1638

	return temperature;
}

/* Adjust Txpower only if temperature variance is greater than threshold. */
S
Stanislaw Gruszka 已提交
1639
#define IL_TEMPERATURE_THRESHOLD   3
1640 1641

/**
S
Stanislaw Gruszka 已提交
1642
 * il4965_is_temp_calib_needed - determines if new calibration is needed
1643 1644 1645 1646
 *
 * If the temperature changed has changed sufficiently, then a recalibration
 * is needed.
 *
S
Stanislaw Gruszka 已提交
1647
 * Assumes caller will replace il->last_temperature once calibration
1648 1649
 * executed.
 */
1650 1651
static int
il4965_is_temp_calib_needed(struct il_priv *il)
1652 1653 1654
{
	int temp_diff;

S
Stanislaw Gruszka 已提交
1655
	if (!test_bit(S_STATS, &il->status)) {
S
Stanislaw Gruszka 已提交
1656
		D_TEMP("Temperature not updated -- no stats.\n");
1657 1658 1659
		return 0;
	}

S
Stanislaw Gruszka 已提交
1660
	temp_diff = il->temperature - il->last_temperature;
1661 1662 1663

	/* get absolute value */
	if (temp_diff < 0) {
1664
		D_POWER("Getting cooler, delta %d\n", temp_diff);
1665 1666
		temp_diff = -temp_diff;
	} else if (temp_diff == 0)
1667
		D_POWER("Temperature unchanged\n");
1668
	else
1669
		D_POWER("Getting warmer, delta %d\n", temp_diff);
1670

S
Stanislaw Gruszka 已提交
1671
	if (temp_diff < IL_TEMPERATURE_THRESHOLD) {
1672
		D_POWER(" => thermal txpower calib not needed\n");
1673 1674 1675
		return 0;
	}

1676
	D_POWER(" => thermal txpower calib needed\n");
1677 1678 1679 1680

	return 1;
}

S
Stanislaw Gruszka 已提交
1681
void
1682
il4965_temperature_calib(struct il_priv *il)
1683 1684 1685
{
	s32 temp;

S
Stanislaw Gruszka 已提交
1686
	temp = il4965_hw_get_temperature(il);
S
Stanislaw Gruszka 已提交
1687
	if (IL_TX_POWER_TEMPERATURE_OUT_OF_RANGE(temp))
1688 1689
		return;

S
Stanislaw Gruszka 已提交
1690 1691
	if (il->temperature != temp) {
		if (il->temperature)
1692 1693 1694
			D_TEMP("Temperature changed " "from %dC to %dC\n",
			       KELVIN_TO_CELSIUS(il->temperature),
			       KELVIN_TO_CELSIUS(temp));
1695
		else
1696 1697
			D_TEMP("Temperature " "initialized to %dC\n",
			       KELVIN_TO_CELSIUS(temp));
1698 1699
	}

S
Stanislaw Gruszka 已提交
1700
	il->temperature = temp;
S
Stanislaw Gruszka 已提交
1701
	set_bit(S_TEMPERATURE, &il->status);
1702

S
Stanislaw Gruszka 已提交
1703
	if (!il->disable_tx_power_cal &&
1704 1705
	    unlikely(!test_bit(S_SCANNING, &il->status)) &&
	    il4965_is_temp_calib_needed(il))
S
Stanislaw Gruszka 已提交
1706
		queue_work(il->workqueue, &il->txpower_work);
1707 1708
}

1709 1710
static u16
il4965_get_hcmd_size(u8 cmd_id, u16 len)
1711 1712
{
	switch (cmd_id) {
1713
	case C_RXON:
S
Stanislaw Gruszka 已提交
1714
		return (u16) sizeof(struct il4965_rxon_cmd);
1715 1716 1717 1718 1719
	default:
		return len;
	}
}

1720 1721
static u16
il4965_build_addsta_hcmd(const struct il_addsta_cmd *cmd, u8 * data)
1722
{
S
Stanislaw Gruszka 已提交
1723
	struct il4965_addsta_cmd *addsta = (struct il4965_addsta_cmd *)data;
1724 1725
	addsta->mode = cmd->mode;
	memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify));
S
Stanislaw Gruszka 已提交
1726
	memcpy(&addsta->key, &cmd->key, sizeof(struct il4965_keyinfo));
1727 1728 1729 1730 1731 1732 1733 1734 1735 1736
	addsta->station_flags = cmd->station_flags;
	addsta->station_flags_msk = cmd->station_flags_msk;
	addsta->tid_disable_tx = cmd->tid_disable_tx;
	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;
	addsta->sleep_tx_count = cmd->sleep_tx_count;
	addsta->reserved1 = cpu_to_le16(0);
	addsta->reserved2 = cpu_to_le16(0);

1737
	return (u16) sizeof(struct il4965_addsta_cmd);
1738 1739
}

S
Stanislaw Gruszka 已提交
1740 1741 1742 1743
static struct il_hcmd_ops il4965_hcmd = {
	.rxon_assoc = il4965_send_rxon_assoc,
	.commit_rxon = il4965_commit_rxon,
	.set_rxon_chain = il4965_set_rxon_chain,
1744 1745
};

1746 1747
static void
il4965_post_scan(struct il_priv *il)
1748 1749 1750 1751 1752
{
	/*
	 * Since setting the RXON may have been deferred while
	 * performing the scan, fire one off if needed
	 */
1753
	if (memcmp(&il->staging, &il->active, sizeof(il->staging)))
1754
		il_commit_rxon(il);
1755 1756
}

1757 1758
static void
il4965_post_associate(struct il_priv *il)
1759
{
1760
	struct ieee80211_vif *vif = il->vif;
1761 1762 1763
	struct ieee80211_conf *conf = NULL;
	int ret = 0;

S
Stanislaw Gruszka 已提交
1764
	if (!vif || !il->is_open)
1765 1766
		return;

S
Stanislaw Gruszka 已提交
1767
	if (test_bit(S_EXIT_PENDING, &il->status))
1768 1769
		return;

S
Stanislaw Gruszka 已提交
1770
	il_scan_cancel_timeout(il, 200);
1771

1772
	conf = &il->hw->conf;
1773

1774
	il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
1775
	il_commit_rxon(il);
1776

1777
	ret = il_send_rxon_timing(il);
1778
	if (ret)
1779
		IL_WARN("RXON timing - " "Attempting to continue.\n");
1780

1781
	il->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
1782

S
Stanislaw Gruszka 已提交
1783
	il_set_rxon_ht(il, &il->current_ht_config);
1784

1785 1786
	if (il->ops->hcmd->set_rxon_chain)
		il->ops->hcmd->set_rxon_chain(il);
1787

1788
	il->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
1789

1790 1791
	D_ASSOC("assoc id %d beacon interval %d\n", vif->bss_conf.aid,
		vif->bss_conf.beacon_int);
1792 1793

	if (vif->bss_conf.use_short_preamble)
1794
		il->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
1795
	else
1796
		il->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
1797

1798
	if (il->staging.flags & RXON_FLG_BAND_24G_MSK) {
1799
		if (vif->bss_conf.use_short_slot)
1800
			il->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
1801
		else
1802
			il->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
1803 1804
	}

1805
	il_commit_rxon(il);
1806

1807
	D_ASSOC("Associated as %d to: %pM\n", vif->bss_conf.aid,
1808
		il->active.bssid_addr);
1809 1810 1811 1812 1813

	switch (vif->type) {
	case NL80211_IFTYPE_STATION:
		break;
	case NL80211_IFTYPE_ADHOC:
S
Stanislaw Gruszka 已提交
1814
		il4965_send_beacon_cmd(il);
1815 1816
		break;
	default:
1817 1818
		IL_ERR("%s Should not be called in %d mode\n", __func__,
		       vif->type);
1819 1820 1821 1822 1823 1824
		break;
	}

	/* the chain noise calibration will enabled PM upon completion
	 * If chain noise has already been run, then we need to enable
	 * power management here */
S
Stanislaw Gruszka 已提交
1825 1826
	if (il->chain_noise_data.state == IL_CHAIN_NOISE_DONE)
		il_power_update_mode(il, false);
1827 1828

	/* Enable Rx differential gain and sensitivity calibrations */
S
Stanislaw Gruszka 已提交
1829 1830
	il4965_chain_noise_reset(il);
	il->start_calib = 1;
1831 1832
}

1833 1834
static void
il4965_config_ap(struct il_priv *il)
1835
{
1836
	struct ieee80211_vif *vif = il->vif;
1837 1838
	int ret = 0;

S
Stanislaw Gruszka 已提交
1839
	lockdep_assert_held(&il->mutex);
1840

S
Stanislaw Gruszka 已提交
1841
	if (test_bit(S_EXIT_PENDING, &il->status))
1842 1843 1844
		return;

	/* The following should be done only at AP bring up */
1845
	if (!il_is_associated(il)) {
1846 1847

		/* RXON - unassoc (to set timing command) */
1848
		il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
1849
		il_commit_rxon(il);
1850 1851

		/* RXON Timing */
1852
		ret = il_send_rxon_timing(il);
1853
		if (ret)
1854
			IL_WARN("RXON timing failed - "
1855
				"Attempting to continue.\n");
1856 1857

		/* AP has all antennas */
1858
		il->chain_noise_data.active_chains = il->hw_params.valid_rx_ant;
S
Stanislaw Gruszka 已提交
1859
		il_set_rxon_ht(il, &il->current_ht_config);
1860 1861
		if (il->ops->hcmd->set_rxon_chain)
			il->ops->hcmd->set_rxon_chain(il);
1862

1863
		il->staging.assoc_id = 0;
1864 1865

		if (vif->bss_conf.use_short_preamble)
1866
			il->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
1867
		else
1868
			il->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
1869

1870
		if (il->staging.flags & RXON_FLG_BAND_24G_MSK) {
1871
			if (vif->bss_conf.use_short_slot)
1872
				il->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
1873
			else
1874
				il->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
1875 1876
		}
		/* need to send beacon cmd before committing assoc RXON! */
S
Stanislaw Gruszka 已提交
1877
		il4965_send_beacon_cmd(il);
1878
		/* restore RXON assoc */
1879
		il->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
1880
		il_commit_rxon(il);
1881
	}
S
Stanislaw Gruszka 已提交
1882
	il4965_send_beacon_cmd(il);
1883 1884
}

S
Stanislaw Gruszka 已提交
1885 1886 1887 1888 1889
static struct il_hcmd_utils_ops il4965_hcmd_utils = {
	.get_hcmd_size = il4965_get_hcmd_size,
	.build_addsta_hcmd = il4965_build_addsta_hcmd,
	.request_scan = il4965_request_scan,
	.post_scan = il4965_post_scan,
1890 1891
};

S
Stanislaw Gruszka 已提交
1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902
static struct il_lib_ops il4965_lib = {
	.txq_update_byte_cnt_tbl = il4965_txq_update_byte_cnt_tbl,
	.txq_attach_buf_to_tfd = il4965_hw_txq_attach_buf_to_tfd,
	.txq_free_tfd = il4965_hw_txq_free_tfd,
	.txq_init = il4965_hw_tx_queue_init,
	.is_valid_rtc_data_addr = il4965_hw_valid_rtc_data_addr,
	.init_alive_start = il4965_init_alive_start,
	.load_ucode = il4965_load_bsm,
	.dump_nic_error_log = il4965_dump_nic_error_log,
	.dump_fh = il4965_dump_fh,
	.set_channel_switch = il4965_hw_channel_switch,
1903
	.apm_ops = {
1904 1905 1906
		    .init = il_apm_init,
		    .config = il4965_nic_config,
		    },
1907
	.eeprom_ops = {
1908 1909 1910 1911
		       .acquire_semaphore = il4965_eeprom_acquire_semaphore,
		       .release_semaphore = il4965_eeprom_release_semaphore,
		       },
	.send_tx_power = il4965_send_tx_power,
S
Stanislaw Gruszka 已提交
1912
	.update_chain_flags = il4965_update_chain_flags,
1913 1914
};

S
Stanislaw Gruszka 已提交
1915 1916 1917 1918 1919
static const struct il_legacy_ops il4965_legacy_ops = {
	.post_associate = il4965_post_associate,
	.config_ap = il4965_config_ap,
	.manage_ibss_station = il4965_manage_ibss_station,
	.update_bcast_stations = il4965_update_bcast_stations,
1920 1921
};

1922
const struct il_ops il4965_ops = {
S
Stanislaw Gruszka 已提交
1923 1924 1925 1926 1927
	.lib = &il4965_lib,
	.hcmd = &il4965_hcmd,
	.utils = &il4965_hcmd_utils,
	.led = &il4965_led_ops,
	.legacy = &il4965_legacy_ops,
1928 1929
};

S
Stanislaw Gruszka 已提交
1930
struct il_cfg il4965_cfg = {
1931
	.name = "Intel(R) Wireless WiFi Link 4965AGN",
1932 1933 1934
	.fw_name_pre = IL4965_FW_PRE,
	.ucode_api_max = IL4965_UCODE_API_MAX,
	.ucode_api_min = IL4965_UCODE_API_MIN,
1935
	.sku = IL_SKU_A | IL_SKU_G | IL_SKU_N,
1936 1937 1938 1939
	.valid_tx_ant = ANT_AB,
	.valid_rx_ant = ANT_ABC,
	.eeprom_ver = EEPROM_4965_EEPROM_VERSION,
	.eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
S
Stanislaw Gruszka 已提交
1940 1941
	.mod_params = &il4965_mod_params,
	.led_mode = IL_LED_BLINK,
1942 1943 1944 1945 1946
	/*
	 * Force use of chains B and C for scan RX on 5 GHz band
	 * because the device has off-channel reception on chain A.
	 */
	.scan_rx_antennas[IEEE80211_BAND_5GHZ] = ANT_BC,
1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960

	.eeprom_size = IL4965_EEPROM_IMG_SIZE,
	.num_of_queues = IL49_NUM_QUEUES,
	.num_of_ampdu_queues = IL49_NUM_AMPDU_QUEUES,
	.pll_cfg_val = 0,
	.set_l0s = true,
	.use_bsm = true,
	.led_compensation = 61,
	.chain_noise_num_beacons = IL4965_CAL_NUM_BEACONS,
	.wd_timeout = IL_DEF_WD_TIMEOUT,
	.temperature_kelvin = true,
	.ucode_tracing = true,
	.sensitivity_calib_by_driver = true,
	.chain_noise_calib_by_driver = true,
1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971

	.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,
		EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS,
		EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS
	},

1972 1973 1974
};

/* Module firmware */
1975
MODULE_FIRMWARE(IL4965_MODULE_FIRMWARE(IL4965_UCODE_API_MAX));