blob: 8f68b94fd74b291eef0234f81ed8b21113e6b231 [file] [log] [blame]
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001/******************************************************************************
2 *
Wey-Yi Guybe663ab2011-02-21 11:27:26 -08003 * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08004 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
20 *
21 * Contact Information:
22 * Intel Linux Wireless <ilw@linux.intel.com>
23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24 *
25 *****************************************************************************/
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/pci.h>
31#include <linux/dma-mapping.h>
32#include <linux/delay.h>
33#include <linux/sched.h>
34#include <linux/skbuff.h>
35#include <linux/netdevice.h>
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -080036#include <net/mac80211.h>
37#include <linux/etherdevice.h>
38#include <asm/unaligned.h>
39
40#include "iwl-eeprom.h"
41#include "iwl-dev.h"
42#include "iwl-core.h"
43#include "iwl-io.h"
44#include "iwl-helpers.h"
Wey-Yi Guybe663ab2011-02-21 11:27:26 -080045#include "iwl-4965-calib.h"
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -080046#include "iwl-sta.h"
Wey-Yi Guybe663ab2011-02-21 11:27:26 -080047#include "iwl-4965.h"
48#include "iwl-4965-debugfs.h"
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -080049
Stanislaw Gruszkafc19cbd2011-08-29 16:59:15 +020050/* Send led command */
51static int
52il4965_send_led_cmd(struct il_priv *il, struct il_led_cmd *led_cmd)
53{
54 struct il_host_cmd cmd = {
55 .id = REPLY_LEDS_CMD,
56 .len = sizeof(struct il_led_cmd),
57 .data = led_cmd,
58 .flags = CMD_ASYNC,
59 .callback = NULL,
60 };
61 u32 reg;
62
63 reg = _il_rd(il, CSR_LED_REG);
64 if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
65 _il_wr(il, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
66
67 return il_send_cmd(il, &cmd);
68}
69
70/* Set led register off */
71void il4965_led_enable(struct il_priv *il)
72{
73 _il_wr(il, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
74}
75
76const struct il_led_ops il4965_led_ops = {
77 .cmd = il4965_send_led_cmd,
78};
79
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +020080static int il4965_send_tx_power(struct il_priv *il);
81static int il4965_hw_get_temperature(struct il_priv *il);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -080082
83/* Highest firmware API version supported */
Stanislaw Gruszkad3175162011-11-15 11:25:42 +010084#define IL4965_UCODE_API_MAX 2
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -080085
86/* Lowest firmware API version supported */
Stanislaw Gruszkad3175162011-11-15 11:25:42 +010087#define IL4965_UCODE_API_MIN 2
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -080088
Stanislaw Gruszkad3175162011-11-15 11:25:42 +010089#define IL4965_FW_PRE "iwlwifi-4965-"
90#define _IL4965_MODULE_FIRMWARE(api) IL4965_FW_PRE #api ".ucode"
91#define IL4965_MODULE_FIRMWARE(api) _IL4965_MODULE_FIRMWARE(api)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -080092
93/* check contents of special bootstrap uCode SRAM */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +020094static int il4965_verify_bsm(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -080095{
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +020096 __le32 *image = il->ucode_boot.v_addr;
97 u32 len = il->ucode_boot.len;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -080098 u32 reg;
99 u32 val;
100
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100101 D_INFO("Begin verify bsm\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800102
103 /* verify BSM SRAM contents */
Stanislaw Gruszkadb54eb52011-08-24 21:06:33 +0200104 val = il_rd_prph(il, BSM_WR_DWCOUNT_REG);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800105 for (reg = BSM_SRAM_LOWER_BOUND;
106 reg < BSM_SRAM_LOWER_BOUND + len;
107 reg += sizeof(u32), image++) {
Stanislaw Gruszkadb54eb52011-08-24 21:06:33 +0200108 val = il_rd_prph(il, reg);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800109 if (val != le32_to_cpu(*image)) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +0200110 IL_ERR("BSM uCode verification failed at "
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800111 "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
112 BSM_SRAM_LOWER_BOUND,
113 reg - BSM_SRAM_LOWER_BOUND, len,
114 val, le32_to_cpu(*image));
115 return -EIO;
116 }
117 }
118
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100119 D_INFO("BSM bootstrap uCode image OK\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800120
121 return 0;
122}
123
124/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200125 * il4965_load_bsm - Load bootstrap instructions
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800126 *
127 * BSM operation:
128 *
129 * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
130 * in special SRAM that does not power down during RFKILL. When powering back
131 * up after power-saving sleeps (or during initial uCode load), the BSM loads
132 * the bootstrap program into the on-board processor, and starts it.
133 *
134 * The bootstrap program loads (via DMA) instructions and data for a new
135 * program from host DRAM locations indicated by the host driver in the
136 * BSM_DRAM_* registers. Once the new program is loaded, it starts
137 * automatically.
138 *
139 * When initializing the NIC, the host driver points the BSM to the
140 * "initialize" uCode image. This uCode sets up some internal data, then
141 * notifies host via "initialize alive" that it is complete.
142 *
143 * The host then replaces the BSM_DRAM_* pointer values to point to the
144 * normal runtime uCode instructions and a backup uCode data cache buffer
145 * (filled initially with starting data values for the on-board processor),
146 * then triggers the "initialize" uCode to load and launch the runtime uCode,
147 * which begins normal operation.
148 *
149 * When doing a power-save shutdown, runtime uCode saves data SRAM into
150 * the backup data cache in DRAM before SRAM is powered down.
151 *
152 * When powering back up, the BSM loads the bootstrap program. This reloads
153 * the runtime uCode instructions and the backup data cache into SRAM,
154 * and re-launches the runtime uCode from where it left off.
155 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200156static int il4965_load_bsm(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800157{
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200158 __le32 *image = il->ucode_boot.v_addr;
159 u32 len = il->ucode_boot.len;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800160 dma_addr_t pinst;
161 dma_addr_t pdata;
162 u32 inst_len;
163 u32 data_len;
164 int i;
165 u32 done;
166 u32 reg_offset;
167 int ret;
168
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100169 D_INFO("Begin load bsm\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800170
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200171 il->ucode_type = UCODE_RT;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800172
173 /* make sure bootstrap program is no larger than BSM's SRAM size */
Stanislaw Gruszkad3175162011-11-15 11:25:42 +0100174 if (len > IL49_MAX_BSM_SIZE)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800175 return -EINVAL;
176
177 /* Tell bootstrap uCode where to find the "Initialize" uCode
178 * in host DRAM ... host DRAM physical address bits 35:4 for 4965.
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200179 * NOTE: il_init_alive_start() will replace these values,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800180 * after the "initialize" uCode has run, to point to
181 * runtime/protocol instructions and backup data cache.
182 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200183 pinst = il->ucode_init.p_addr >> 4;
184 pdata = il->ucode_init_data.p_addr >> 4;
185 inst_len = il->ucode_init.len;
186 data_len = il->ucode_init_data.len;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800187
Stanislaw Gruszkadb54eb52011-08-24 21:06:33 +0200188 il_wr_prph(il, BSM_DRAM_INST_PTR_REG, pinst);
189 il_wr_prph(il, BSM_DRAM_DATA_PTR_REG, pdata);
190 il_wr_prph(il, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
191 il_wr_prph(il, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800192
193 /* Fill BSM memory with bootstrap instructions */
194 for (reg_offset = BSM_SRAM_LOWER_BOUND;
195 reg_offset < BSM_SRAM_LOWER_BOUND + len;
196 reg_offset += sizeof(u32), image++)
Stanislaw Gruszkadb54eb52011-08-24 21:06:33 +0200197 _il_wr_prph(il, reg_offset, le32_to_cpu(*image));
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800198
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200199 ret = il4965_verify_bsm(il);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800200 if (ret)
201 return ret;
202
203 /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
Stanislaw Gruszkadb54eb52011-08-24 21:06:33 +0200204 il_wr_prph(il, BSM_WR_MEM_SRC_REG, 0x0);
205 il_wr_prph(il,
Stanislaw Gruszkad3175162011-11-15 11:25:42 +0100206 BSM_WR_MEM_DST_REG, IL49_RTC_INST_LOWER_BOUND);
Stanislaw Gruszkadb54eb52011-08-24 21:06:33 +0200207 il_wr_prph(il, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800208
209 /* Load bootstrap code into instruction SRAM now,
210 * to prepare to load "initialize" uCode */
Stanislaw Gruszkadb54eb52011-08-24 21:06:33 +0200211 il_wr_prph(il, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800212
213 /* Wait for load of bootstrap uCode to finish */
214 for (i = 0; i < 100; i++) {
Stanislaw Gruszkadb54eb52011-08-24 21:06:33 +0200215 done = il_rd_prph(il, BSM_WR_CTRL_REG);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800216 if (!(done & BSM_WR_CTRL_REG_BIT_START))
217 break;
218 udelay(10);
219 }
220 if (i < 100)
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100221 D_INFO("BSM write complete, poll %d iterations\n", i);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800222 else {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +0200223 IL_ERR("BSM write did not complete!\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800224 return -EIO;
225 }
226
227 /* Enable future boot loads whenever power management unit triggers it
228 * (e.g. when powering back up after power-save shutdown) */
Stanislaw Gruszkadb54eb52011-08-24 21:06:33 +0200229 il_wr_prph(il,
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800230 BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800231
232
233 return 0;
234}
235
236/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200237 * il4965_set_ucode_ptrs - Set uCode address location
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800238 *
239 * Tell initialization uCode where to find runtime uCode.
240 *
241 * BSM registers initially contain pointers to initialization uCode.
242 * We need to replace them to load runtime uCode inst and data,
243 * and to save runtime data when powering down.
244 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200245static int il4965_set_ucode_ptrs(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800246{
247 dma_addr_t pinst;
248 dma_addr_t pdata;
249 int ret = 0;
250
251 /* bits 35:4 for 4965 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200252 pinst = il->ucode_code.p_addr >> 4;
253 pdata = il->ucode_data_backup.p_addr >> 4;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800254
255 /* Tell bootstrap uCode where to find image to load */
Stanislaw Gruszkadb54eb52011-08-24 21:06:33 +0200256 il_wr_prph(il, BSM_DRAM_INST_PTR_REG, pinst);
257 il_wr_prph(il, BSM_DRAM_DATA_PTR_REG, pdata);
258 il_wr_prph(il, BSM_DRAM_DATA_BYTECOUNT_REG,
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200259 il->ucode_data.len);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800260
261 /* Inst byte count must be last to set up, bit 31 signals uCode
262 * that all new ptr/size info is in place */
Stanislaw Gruszkadb54eb52011-08-24 21:06:33 +0200263 il_wr_prph(il, BSM_DRAM_INST_BYTECOUNT_REG,
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200264 il->ucode_code.len | BSM_DRAM_INST_LOAD);
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100265 D_INFO("Runtime uCode pointers are set.\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800266
267 return ret;
268}
269
270/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200271 * il4965_init_alive_start - Called after REPLY_ALIVE notification received
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800272 *
273 * Called after REPLY_ALIVE notification received from "initialize" uCode.
274 *
275 * The 4965 "initialize" ALIVE reply contains calibration data for:
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200276 * Voltage, temperature, and MIMO tx gain correction, now stored in il
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800277 * (3945 does not contain this data).
278 *
279 * Tell "initialize" uCode to go ahead and load the runtime uCode.
280*/
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200281static void il4965_init_alive_start(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800282{
283 /* Bootstrap uCode has loaded initialize uCode ... verify inst image.
284 * This is a paranoid check, because we would not have gotten the
285 * "initialize" alive if code weren't properly loaded. */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200286 if (il4965_verify_ucode(il)) {
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800287 /* Runtime instruction load was bad;
288 * take it all the way back down so we can try again */
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100289 D_INFO("Bad \"initialize\" uCode load.\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800290 goto restart;
291 }
292
293 /* Calculate temperature */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200294 il->temperature = il4965_hw_get_temperature(il);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800295
296 /* Send pointers to protocol/runtime uCode image ... init code will
297 * load and launch runtime uCode, which will send us another "Alive"
298 * notification. */
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100299 D_INFO("Initialization Alive received.\n");
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200300 if (il4965_set_ucode_ptrs(il)) {
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800301 /* Runtime instruction load won't happen;
302 * take it all the way back down so we can try again */
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100303 D_INFO("Couldn't set up uCode pointers.\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800304 goto restart;
305 }
306 return;
307
308restart:
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200309 queue_work(il->workqueue, &il->restart);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800310}
311
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800312static bool iw4965_is_ht40_channel(__le32 rxon_flags)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800313{
314 int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK)
315 >> RXON_FLG_CHANNEL_MODE_POS;
Stanislaw Gruszka232913b2011-08-26 10:45:16 +0200316 return (chan_mod == CHANNEL_MODE_PURE_40 ||
317 chan_mod == CHANNEL_MODE_MIXED);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800318}
319
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200320static void il4965_nic_config(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800321{
322 unsigned long flags;
323 u16 radio_cfg;
324
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200325 spin_lock_irqsave(&il->lock, flags);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800326
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200327 radio_cfg = il_eeprom_query16(il, EEPROM_RADIO_CONFIG);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800328
329 /* write radio config values to register */
330 if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) == EEPROM_4965_RF_CFG_TYPE_MAX)
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200331 il_set_bit(il, CSR_HW_IF_CONFIG_REG,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800332 EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
333 EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
334 EEPROM_RF_CFG_DASH_MSK(radio_cfg));
335
336 /* set CSR_HW_CONFIG_REG for uCode use */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200337 il_set_bit(il, CSR_HW_IF_CONFIG_REG,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800338 CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
339 CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
340
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200341 il->calib_info = (struct il_eeprom_calib_info *)
342 il_eeprom_query_addr(il,
Wey-Yi Guybe663ab2011-02-21 11:27:26 -0800343 EEPROM_4965_CALIB_TXPOWER_OFFSET);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800344
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200345 spin_unlock_irqrestore(&il->lock, flags);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800346}
347
348/* Reset differential Rx gains in NIC to prepare for chain noise calibration.
349 * Called after every association, but this runs only once!
350 * ... once chain noise is calibrated the first time, it's good forever. */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200351static void il4965_chain_noise_reset(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800352{
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200353 struct il_chain_noise_data *data = &(il->chain_noise_data);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800354
Stanislaw Gruszka232913b2011-08-26 10:45:16 +0200355 if (data->state == IL_CHAIN_NOISE_ALIVE &&
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200356 il_is_any_associated(il)) {
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200357 struct il_calib_diff_gain_cmd cmd;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800358
359 /* clear data for chain noise calibration algorithm */
360 data->chain_noise_a = 0;
361 data->chain_noise_b = 0;
362 data->chain_noise_c = 0;
363 data->chain_signal_a = 0;
364 data->chain_signal_b = 0;
365 data->chain_signal_c = 0;
366 data->beacon_count = 0;
367
368 memset(&cmd, 0, sizeof(cmd));
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200369 cmd.hdr.op_code = IL_PHY_CALIBRATE_DIFF_GAIN_CMD;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800370 cmd.diff_gain_a = 0;
371 cmd.diff_gain_b = 0;
372 cmd.diff_gain_c = 0;
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200373 if (il_send_cmd_pdu(il, REPLY_PHY_CALIBRATION_CMD,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800374 sizeof(cmd), &cmd))
Stanislaw Gruszka9406f792011-08-18 22:07:57 +0200375 IL_ERR(
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800376 "Could not send REPLY_PHY_CALIBRATION_CMD\n");
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200377 data->state = IL_CHAIN_NOISE_ACCUMULATE;
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100378 D_CALIB("Run chain_noise_calibrate\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800379 }
380}
381
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200382static struct il_sensitivity_ranges il4965_sensitivity = {
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800383 .min_nrg_cck = 97,
384 .max_nrg_cck = 0, /* not used, set to 0 */
385
386 .auto_corr_min_ofdm = 85,
387 .auto_corr_min_ofdm_mrc = 170,
388 .auto_corr_min_ofdm_x1 = 105,
389 .auto_corr_min_ofdm_mrc_x1 = 220,
390
391 .auto_corr_max_ofdm = 120,
392 .auto_corr_max_ofdm_mrc = 210,
393 .auto_corr_max_ofdm_x1 = 140,
394 .auto_corr_max_ofdm_mrc_x1 = 270,
395
396 .auto_corr_min_cck = 125,
397 .auto_corr_max_cck = 200,
398 .auto_corr_min_cck_mrc = 200,
399 .auto_corr_max_cck_mrc = 400,
400
401 .nrg_th_cck = 100,
402 .nrg_th_ofdm = 100,
403
404 .barker_corr_th_min = 190,
405 .barker_corr_th_min_mrc = 390,
406 .nrg_th_cca = 62,
407};
408
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200409static void il4965_set_ct_threshold(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800410{
411 /* want Kelvin */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200412 il->hw_params.ct_kill_threshold =
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800413 CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY);
414}
415
416/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200417 * il4965_hw_set_hw_params
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800418 *
419 * Called when initializing driver
420 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200421static int il4965_hw_set_hw_params(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800422{
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200423 if (il->cfg->mod_params->num_of_queues >= IL_MIN_NUM_QUEUES &&
Stanislaw Gruszkad3175162011-11-15 11:25:42 +0100424 il->cfg->mod_params->num_of_queues <= IL49_NUM_QUEUES)
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200425 il->cfg->base_params->num_of_queues =
426 il->cfg->mod_params->num_of_queues;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800427
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200428 il->hw_params.max_txq_num = il->cfg->base_params->num_of_queues;
429 il->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM;
430 il->hw_params.scd_bc_tbls_size =
431 il->cfg->base_params->num_of_queues *
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200432 sizeof(struct il4965_scd_bc_tbl);
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200433 il->hw_params.tfd_size = sizeof(struct il_tfd);
Stanislaw Gruszkad3175162011-11-15 11:25:42 +0100434 il->hw_params.max_stations = IL4965_STATION_COUNT;
Stanislaw Gruszka7c2cde22011-11-15 11:29:04 +0100435 il->ctx.bcast_sta_id = IL4965_BROADCAST_ID;
Stanislaw Gruszkad3175162011-11-15 11:25:42 +0100436 il->hw_params.max_data_size = IL49_RTC_DATA_SIZE;
437 il->hw_params.max_inst_size = IL49_RTC_INST_SIZE;
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200438 il->hw_params.max_bsm_size = BSM_SRAM_SIZE;
439 il->hw_params.ht40_channel = BIT(IEEE80211_BAND_5GHZ);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800440
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200441 il->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800442
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200443 il->hw_params.tx_chains_num = il4965_num_of_ant(il->cfg->valid_tx_ant);
444 il->hw_params.rx_chains_num = il4965_num_of_ant(il->cfg->valid_rx_ant);
445 il->hw_params.valid_tx_ant = il->cfg->valid_tx_ant;
446 il->hw_params.valid_rx_ant = il->cfg->valid_rx_ant;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800447
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200448 il4965_set_ct_threshold(il);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800449
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200450 il->hw_params.sens = &il4965_sensitivity;
Stanislaw Gruszkad3175162011-11-15 11:25:42 +0100451 il->hw_params.beacon_time_tsf_bits = IL4965_EXT_BEACON_TIME_POS;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800452
453 return 0;
454}
455
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200456static s32 il4965_math_div_round(s32 num, s32 denom, s32 *res)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800457{
458 s32 sign = 1;
459
460 if (num < 0) {
461 sign = -sign;
462 num = -num;
463 }
464 if (denom < 0) {
465 sign = -sign;
466 denom = -denom;
467 }
468 *res = 1;
469 *res = ((num * 2 + denom) / (denom * 2)) * sign;
470
471 return 1;
472}
473
474/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200475 * il4965_get_voltage_compensation - Power supply voltage comp for txpower
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800476 *
477 * Determines power supply voltage compensation for txpower calculations.
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +0100478 * Returns number of 1/2-dB steps to subtract from gain table idx,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800479 * to compensate for difference between power supply voltage during
480 * factory measurements, vs. current power supply voltage.
481 *
482 * Voltage indication is higher for lower voltage.
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +0100483 * Lower voltage requires more gain (lower gain table idx).
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800484 */
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200485static s32 il4965_get_voltage_compensation(s32 eeprom_voltage,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800486 s32 current_voltage)
487{
488 s32 comp = 0;
489
Stanislaw Gruszka232913b2011-08-26 10:45:16 +0200490 if (TX_POWER_IL_ILLEGAL_VOLTAGE == eeprom_voltage ||
491 TX_POWER_IL_ILLEGAL_VOLTAGE == current_voltage)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800492 return 0;
493
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200494 il4965_math_div_round(current_voltage - eeprom_voltage,
495 TX_POWER_IL_VOLTAGE_CODES_PER_03V, &comp);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800496
497 if (current_voltage > eeprom_voltage)
498 comp *= 2;
499 if ((comp < -2) || (comp > 2))
500 comp = 0;
501
502 return comp;
503}
504
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200505static s32 il4965_get_tx_atten_grp(u16 channel)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800506{
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200507 if (channel >= CALIB_IL_TX_ATTEN_GR5_FCH &&
508 channel <= CALIB_IL_TX_ATTEN_GR5_LCH)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800509 return CALIB_CH_GROUP_5;
510
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200511 if (channel >= CALIB_IL_TX_ATTEN_GR1_FCH &&
512 channel <= CALIB_IL_TX_ATTEN_GR1_LCH)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800513 return CALIB_CH_GROUP_1;
514
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200515 if (channel >= CALIB_IL_TX_ATTEN_GR2_FCH &&
516 channel <= CALIB_IL_TX_ATTEN_GR2_LCH)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800517 return CALIB_CH_GROUP_2;
518
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200519 if (channel >= CALIB_IL_TX_ATTEN_GR3_FCH &&
520 channel <= CALIB_IL_TX_ATTEN_GR3_LCH)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800521 return CALIB_CH_GROUP_3;
522
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200523 if (channel >= CALIB_IL_TX_ATTEN_GR4_FCH &&
524 channel <= CALIB_IL_TX_ATTEN_GR4_LCH)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800525 return CALIB_CH_GROUP_4;
526
Greg Dietsche8e638182011-06-02 21:06:08 -0500527 return -EINVAL;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800528}
529
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200530static u32 il4965_get_sub_band(const struct il_priv *il, u32 channel)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800531{
532 s32 b = -1;
533
534 for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) {
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200535 if (il->calib_info->band_info[b].ch_from == 0)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800536 continue;
537
Stanislaw Gruszka232913b2011-08-26 10:45:16 +0200538 if (channel >= il->calib_info->band_info[b].ch_from &&
539 channel <= il->calib_info->band_info[b].ch_to)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800540 break;
541 }
542
543 return b;
544}
545
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200546static s32 il4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800547{
548 s32 val;
549
550 if (x2 == x1)
551 return y1;
552 else {
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200553 il4965_math_div_round((x2 - x) * (y1 - y2), (x2 - x1), &val);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800554 return val + y2;
555 }
556}
557
558/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200559 * il4965_interpolate_chan - Interpolate factory measurements for one channel
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800560 *
561 * Interpolates factory measurements from the two sample channels within a
562 * sub-band, to apply to channel of interest. Interpolation is proportional to
563 * differences in channel frequencies, which is proportional to differences
564 * in channel number.
565 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200566static int il4965_interpolate_chan(struct il_priv *il, u32 channel,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200567 struct il_eeprom_calib_ch_info *chan_info)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800568{
569 s32 s = -1;
570 u32 c;
571 u32 m;
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200572 const struct il_eeprom_calib_measure *m1;
573 const struct il_eeprom_calib_measure *m2;
574 struct il_eeprom_calib_measure *omeas;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800575 u32 ch_i1;
576 u32 ch_i2;
577
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200578 s = il4965_get_sub_band(il, channel);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800579 if (s >= EEPROM_TX_POWER_BANDS) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +0200580 IL_ERR("Tx Power can not find channel %d\n", channel);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800581 return -1;
582 }
583
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200584 ch_i1 = il->calib_info->band_info[s].ch1.ch_num;
585 ch_i2 = il->calib_info->band_info[s].ch2.ch_num;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800586 chan_info->ch_num = (u8) channel;
587
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100588 D_TXPOWER("channel %d subband %d factory cal ch %d & %d\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800589 channel, s, ch_i1, ch_i2);
590
591 for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) {
592 for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) {
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200593 m1 = &(il->calib_info->band_info[s].ch1.
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800594 measurements[c][m]);
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200595 m2 = &(il->calib_info->band_info[s].ch2.
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800596 measurements[c][m]);
597 omeas = &(chan_info->measurements[c][m]);
598
599 omeas->actual_pow =
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200600 (u8) il4965_interpolate_value(channel, ch_i1,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800601 m1->actual_pow,
602 ch_i2,
603 m2->actual_pow);
604 omeas->gain_idx =
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200605 (u8) il4965_interpolate_value(channel, ch_i1,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800606 m1->gain_idx, ch_i2,
607 m2->gain_idx);
608 omeas->temperature =
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200609 (u8) il4965_interpolate_value(channel, ch_i1,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800610 m1->temperature,
611 ch_i2,
612 m2->temperature);
613 omeas->pa_det =
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200614 (s8) il4965_interpolate_value(channel, ch_i1,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800615 m1->pa_det, ch_i2,
616 m2->pa_det);
617
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100618 D_TXPOWER(
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800619 "chain %d meas %d AP1=%d AP2=%d AP=%d\n", c, m,
620 m1->actual_pow, m2->actual_pow, omeas->actual_pow);
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100621 D_TXPOWER(
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800622 "chain %d meas %d NI1=%d NI2=%d NI=%d\n", c, m,
623 m1->gain_idx, m2->gain_idx, omeas->gain_idx);
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100624 D_TXPOWER(
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800625 "chain %d meas %d PA1=%d PA2=%d PA=%d\n", c, m,
626 m1->pa_det, m2->pa_det, omeas->pa_det);
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100627 D_TXPOWER(
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800628 "chain %d meas %d T1=%d T2=%d T=%d\n", c, m,
629 m1->temperature, m2->temperature,
630 omeas->temperature);
631 }
632 }
633
634 return 0;
635}
636
637/* bit-rate-dependent table to prevent Tx distortion, in half-dB units,
638 * for OFDM 6, 12, 18, 24, 36, 48, 54, 60 MBit, and CCK all rates. */
639static s32 back_off_table[] = {
640 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 20 MHz */
641 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 20 MHz */
642 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 40 MHz */
643 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 40 MHz */
644 10 /* CCK */
645};
646
647/* Thermal compensation values for txpower for various frequency ranges ...
648 * ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust */
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200649static struct il4965_txpower_comp_entry {
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800650 s32 degrees_per_05db_a;
651 s32 degrees_per_05db_a_denom;
652} tx_power_cmp_tble[CALIB_CH_GROUP_MAX] = {
653 {9, 2}, /* group 0 5.2, ch 34-43 */
654 {4, 1}, /* group 1 5.2, ch 44-70 */
655 {4, 1}, /* group 2 5.2, ch 71-124 */
656 {4, 1}, /* group 3 5.2, ch 125-200 */
657 {3, 1} /* group 4 2.4, ch all */
658};
659
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +0100660static s32 get_min_power_idx(s32 rate_power_idx, u32 band)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800661{
662 if (!band) {
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +0100663 if ((rate_power_idx & 7) <= 4)
Stanislaw Gruszka2d09b062011-08-26 16:10:40 +0200664 return MIN_TX_GAIN_IDX_52GHZ_EXT;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800665 }
Stanislaw Gruszka2d09b062011-08-26 16:10:40 +0200666 return MIN_TX_GAIN_IDX;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800667}
668
669struct gain_entry {
670 u8 dsp;
671 u8 radio;
672};
673
674static const struct gain_entry gain_table[2][108] = {
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +0100675 /* 5.2GHz power gain idx table */
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800676 {
677 {123, 0x3F}, /* highest txpower */
678 {117, 0x3F},
679 {110, 0x3F},
680 {104, 0x3F},
681 {98, 0x3F},
682 {110, 0x3E},
683 {104, 0x3E},
684 {98, 0x3E},
685 {110, 0x3D},
686 {104, 0x3D},
687 {98, 0x3D},
688 {110, 0x3C},
689 {104, 0x3C},
690 {98, 0x3C},
691 {110, 0x3B},
692 {104, 0x3B},
693 {98, 0x3B},
694 {110, 0x3A},
695 {104, 0x3A},
696 {98, 0x3A},
697 {110, 0x39},
698 {104, 0x39},
699 {98, 0x39},
700 {110, 0x38},
701 {104, 0x38},
702 {98, 0x38},
703 {110, 0x37},
704 {104, 0x37},
705 {98, 0x37},
706 {110, 0x36},
707 {104, 0x36},
708 {98, 0x36},
709 {110, 0x35},
710 {104, 0x35},
711 {98, 0x35},
712 {110, 0x34},
713 {104, 0x34},
714 {98, 0x34},
715 {110, 0x33},
716 {104, 0x33},
717 {98, 0x33},
718 {110, 0x32},
719 {104, 0x32},
720 {98, 0x32},
721 {110, 0x31},
722 {104, 0x31},
723 {98, 0x31},
724 {110, 0x30},
725 {104, 0x30},
726 {98, 0x30},
727 {110, 0x25},
728 {104, 0x25},
729 {98, 0x25},
730 {110, 0x24},
731 {104, 0x24},
732 {98, 0x24},
733 {110, 0x23},
734 {104, 0x23},
735 {98, 0x23},
736 {110, 0x22},
737 {104, 0x18},
738 {98, 0x18},
739 {110, 0x17},
740 {104, 0x17},
741 {98, 0x17},
742 {110, 0x16},
743 {104, 0x16},
744 {98, 0x16},
745 {110, 0x15},
746 {104, 0x15},
747 {98, 0x15},
748 {110, 0x14},
749 {104, 0x14},
750 {98, 0x14},
751 {110, 0x13},
752 {104, 0x13},
753 {98, 0x13},
754 {110, 0x12},
755 {104, 0x08},
756 {98, 0x08},
757 {110, 0x07},
758 {104, 0x07},
759 {98, 0x07},
760 {110, 0x06},
761 {104, 0x06},
762 {98, 0x06},
763 {110, 0x05},
764 {104, 0x05},
765 {98, 0x05},
766 {110, 0x04},
767 {104, 0x04},
768 {98, 0x04},
769 {110, 0x03},
770 {104, 0x03},
771 {98, 0x03},
772 {110, 0x02},
773 {104, 0x02},
774 {98, 0x02},
775 {110, 0x01},
776 {104, 0x01},
777 {98, 0x01},
778 {110, 0x00},
779 {104, 0x00},
780 {98, 0x00},
781 {93, 0x00},
782 {88, 0x00},
783 {83, 0x00},
784 {78, 0x00},
785 },
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +0100786 /* 2.4GHz power gain idx table */
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800787 {
788 {110, 0x3f}, /* highest txpower */
789 {104, 0x3f},
790 {98, 0x3f},
791 {110, 0x3e},
792 {104, 0x3e},
793 {98, 0x3e},
794 {110, 0x3d},
795 {104, 0x3d},
796 {98, 0x3d},
797 {110, 0x3c},
798 {104, 0x3c},
799 {98, 0x3c},
800 {110, 0x3b},
801 {104, 0x3b},
802 {98, 0x3b},
803 {110, 0x3a},
804 {104, 0x3a},
805 {98, 0x3a},
806 {110, 0x39},
807 {104, 0x39},
808 {98, 0x39},
809 {110, 0x38},
810 {104, 0x38},
811 {98, 0x38},
812 {110, 0x37},
813 {104, 0x37},
814 {98, 0x37},
815 {110, 0x36},
816 {104, 0x36},
817 {98, 0x36},
818 {110, 0x35},
819 {104, 0x35},
820 {98, 0x35},
821 {110, 0x34},
822 {104, 0x34},
823 {98, 0x34},
824 {110, 0x33},
825 {104, 0x33},
826 {98, 0x33},
827 {110, 0x32},
828 {104, 0x32},
829 {98, 0x32},
830 {110, 0x31},
831 {104, 0x31},
832 {98, 0x31},
833 {110, 0x30},
834 {104, 0x30},
835 {98, 0x30},
836 {110, 0x6},
837 {104, 0x6},
838 {98, 0x6},
839 {110, 0x5},
840 {104, 0x5},
841 {98, 0x5},
842 {110, 0x4},
843 {104, 0x4},
844 {98, 0x4},
845 {110, 0x3},
846 {104, 0x3},
847 {98, 0x3},
848 {110, 0x2},
849 {104, 0x2},
850 {98, 0x2},
851 {110, 0x1},
852 {104, 0x1},
853 {98, 0x1},
854 {110, 0x0},
855 {104, 0x0},
856 {98, 0x0},
857 {97, 0},
858 {96, 0},
859 {95, 0},
860 {94, 0},
861 {93, 0},
862 {92, 0},
863 {91, 0},
864 {90, 0},
865 {89, 0},
866 {88, 0},
867 {87, 0},
868 {86, 0},
869 {85, 0},
870 {84, 0},
871 {83, 0},
872 {82, 0},
873 {81, 0},
874 {80, 0},
875 {79, 0},
876 {78, 0},
877 {77, 0},
878 {76, 0},
879 {75, 0},
880 {74, 0},
881 {73, 0},
882 {72, 0},
883 {71, 0},
884 {70, 0},
885 {69, 0},
886 {68, 0},
887 {67, 0},
888 {66, 0},
889 {65, 0},
890 {64, 0},
891 {63, 0},
892 {62, 0},
893 {61, 0},
894 {60, 0},
895 {59, 0},
896 }
897};
898
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200899static int il4965_fill_txpower_tbl(struct il_priv *il, u8 band, u16 channel,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800900 u8 is_ht40, u8 ctrl_chan_high,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200901 struct il4965_tx_power_db *tx_power_tbl)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800902{
903 u8 saturation_power;
904 s32 target_power;
905 s32 user_target_power;
906 s32 power_limit;
907 s32 current_temp;
908 s32 reg_limit;
909 s32 current_regulatory;
910 s32 txatten_grp = CALIB_CH_GROUP_MAX;
911 int i;
912 int c;
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200913 const struct il_channel_info *ch_info = NULL;
914 struct il_eeprom_calib_ch_info ch_eeprom_info;
915 const struct il_eeprom_calib_measure *measurement;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800916 s16 voltage;
917 s32 init_voltage;
918 s32 voltage_compensation;
919 s32 degrees_per_05db_num;
920 s32 degrees_per_05db_denom;
921 s32 factory_temp;
922 s32 temperature_comp[2];
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +0100923 s32 factory_gain_idx[2];
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800924 s32 factory_actual_pwr[2];
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +0100925 s32 power_idx;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800926
927 /* tx_power_user_lmt is in dBm, convert to half-dBm (half-dB units
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +0100928 * are used for idxing into txpower table) */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200929 user_target_power = 2 * il->tx_power_user_lmt;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800930
931 /* Get current (RXON) channel, band, width */
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100932 D_TXPOWER("chan %d band %d is_ht40 %d\n", channel, band,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800933 is_ht40);
934
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200935 ch_info = il_get_channel_info(il, il->band, channel);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800936
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200937 if (!il_is_channel_valid(ch_info))
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800938 return -EINVAL;
939
940 /* get txatten group, used to select 1) thermal txpower adjustment
941 * and 2) mimo txpower balance between Tx chains. */
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200942 txatten_grp = il4965_get_tx_atten_grp(channel);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800943 if (txatten_grp < 0) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +0200944 IL_ERR("Can't find txatten group for channel %d.\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800945 channel);
Greg Dietsche5c30c762011-06-02 21:06:09 -0500946 return txatten_grp;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800947 }
948
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100949 D_TXPOWER("channel %d belongs to txatten group %d\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800950 channel, txatten_grp);
951
952 if (is_ht40) {
953 if (ctrl_chan_high)
954 channel -= 2;
955 else
956 channel += 2;
957 }
958
959 /* hardware txpower limits ...
960 * saturation (clipping distortion) txpowers are in half-dBm */
961 if (band)
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200962 saturation_power = il->calib_info->saturation_power24;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800963 else
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200964 saturation_power = il->calib_info->saturation_power52;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800965
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200966 if (saturation_power < IL_TX_POWER_SATURATION_MIN ||
967 saturation_power > IL_TX_POWER_SATURATION_MAX) {
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800968 if (band)
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200969 saturation_power = IL_TX_POWER_DEFAULT_SATURATION_24;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800970 else
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200971 saturation_power = IL_TX_POWER_DEFAULT_SATURATION_52;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800972 }
973
974 /* regulatory txpower limits ... reg_limit values are in half-dBm,
975 * max_power_avg values are in dBm, convert * 2 */
976 if (is_ht40)
977 reg_limit = ch_info->ht40_max_power_avg * 2;
978 else
979 reg_limit = ch_info->max_power_avg * 2;
980
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200981 if ((reg_limit < IL_TX_POWER_REGULATORY_MIN) ||
982 (reg_limit > IL_TX_POWER_REGULATORY_MAX)) {
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800983 if (band)
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200984 reg_limit = IL_TX_POWER_DEFAULT_REGULATORY_24;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800985 else
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200986 reg_limit = IL_TX_POWER_DEFAULT_REGULATORY_52;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800987 }
988
989 /* Interpolate txpower calibration values for this channel,
990 * based on factory calibration tests on spaced channels. */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200991 il4965_interpolate_chan(il, channel, &ch_eeprom_info);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800992
993 /* calculate tx gain adjustment based on power supply voltage */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +0200994 voltage = le16_to_cpu(il->calib_info->voltage);
995 init_voltage = (s32)le32_to_cpu(il->card_alive_init.voltage);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800996 voltage_compensation =
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +0200997 il4965_get_voltage_compensation(voltage, init_voltage);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -0800998
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +0100999 D_TXPOWER("curr volt %d eeprom volt %d volt comp %d\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001000 init_voltage,
1001 voltage, voltage_compensation);
1002
1003 /* get current temperature (Celsius) */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001004 current_temp = max(il->temperature, IL_TX_POWER_TEMPERATURE_MIN);
1005 current_temp = min(il->temperature, IL_TX_POWER_TEMPERATURE_MAX);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001006 current_temp = KELVIN_TO_CELSIUS(current_temp);
1007
1008 /* select thermal txpower adjustment params, based on channel group
1009 * (same frequency group used for mimo txatten adjustment) */
1010 degrees_per_05db_num =
1011 tx_power_cmp_tble[txatten_grp].degrees_per_05db_a;
1012 degrees_per_05db_denom =
1013 tx_power_cmp_tble[txatten_grp].degrees_per_05db_a_denom;
1014
1015 /* get per-chain txpower values from factory measurements */
1016 for (c = 0; c < 2; c++) {
1017 measurement = &ch_eeprom_info.measurements[c][1];
1018
1019 /* txgain adjustment (in half-dB steps) based on difference
1020 * between factory and current temperature */
1021 factory_temp = measurement->temperature;
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001022 il4965_math_div_round((current_temp - factory_temp) *
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001023 degrees_per_05db_denom,
1024 degrees_per_05db_num,
1025 &temperature_comp[c]);
1026
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001027 factory_gain_idx[c] = measurement->gain_idx;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001028 factory_actual_pwr[c] = measurement->actual_pow;
1029
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001030 D_TXPOWER("chain = %d\n", c);
1031 D_TXPOWER("fctry tmp %d, "
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001032 "curr tmp %d, comp %d steps\n",
1033 factory_temp, current_temp,
1034 temperature_comp[c]);
1035
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001036 D_TXPOWER("fctry idx %d, fctry pwr %d\n",
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001037 factory_gain_idx[c],
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001038 factory_actual_pwr[c]);
1039 }
1040
1041 /* for each of 33 bit-rates (including 1 for CCK) */
Stanislaw Gruszka3b98c7f2011-08-26 16:29:35 +02001042 for (i = 0; i < POWER_TBL_NUM_ENTRIES; i++) {
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001043 u8 is_mimo_rate;
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001044 union il4965_tx_power_dual_stream tx_power;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001045
1046 /* for mimo, reduce each chain's txpower by half
1047 * (3dB, 6 steps), so total output power is regulatory
1048 * compliant. */
1049 if (i & 0x8) {
1050 current_regulatory = reg_limit -
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001051 IL_TX_POWER_MIMO_REGULATORY_COMPENSATION;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001052 is_mimo_rate = 1;
1053 } else {
1054 current_regulatory = reg_limit;
1055 is_mimo_rate = 0;
1056 }
1057
1058 /* find txpower limit, either hardware or regulatory */
1059 power_limit = saturation_power - back_off_table[i];
1060 if (power_limit > current_regulatory)
1061 power_limit = current_regulatory;
1062
1063 /* reduce user's txpower request if necessary
1064 * for this rate on this channel */
1065 target_power = user_target_power;
1066 if (target_power > power_limit)
1067 target_power = power_limit;
1068
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001069 D_TXPOWER("rate %d sat %d reg %d usr %d tgt %d\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001070 i, saturation_power - back_off_table[i],
1071 current_regulatory, user_target_power,
1072 target_power);
1073
1074 /* for each of 2 Tx chains (radio transmitters) */
1075 for (c = 0; c < 2; c++) {
1076 s32 atten_value;
1077
1078 if (is_mimo_rate)
1079 atten_value =
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001080 (s32)le32_to_cpu(il->card_alive_init.
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001081 tx_atten[txatten_grp][c]);
1082 else
1083 atten_value = 0;
1084
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001085 /* calculate idx; higher idx means lower txpower */
1086 power_idx = (u8) (factory_gain_idx[c] -
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001087 (target_power -
1088 factory_actual_pwr[c]) -
1089 temperature_comp[c] -
1090 voltage_compensation +
1091 atten_value);
1092
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001093/* D_TXPOWER("calculated txpower idx %d\n",
1094 power_idx); */
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001095
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001096 if (power_idx < get_min_power_idx(i, band))
1097 power_idx = get_min_power_idx(i, band);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001098
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001099 /* adjust 5 GHz idx to support negative idxes */
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001100 if (!band)
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001101 power_idx += 9;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001102
1103 /* CCK, rate 32, reduce txpower for CCK */
Stanislaw Gruszka3b98c7f2011-08-26 16:29:35 +02001104 if (i == POWER_TBL_CCK_ENTRY)
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001105 power_idx +=
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001106 IL_TX_POWER_CCK_COMPENSATION_C_STEP;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001107
1108 /* stay within the table! */
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001109 if (power_idx > 107) {
1110 IL_WARN("txpower idx %d > 107\n",
1111 power_idx);
1112 power_idx = 107;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001113 }
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001114 if (power_idx < 0) {
1115 IL_WARN("txpower idx %d < 0\n",
1116 power_idx);
1117 power_idx = 0;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001118 }
1119
1120 /* fill txpower command for this rate/chain */
1121 tx_power.s.radio_tx_gain[c] =
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001122 gain_table[band][power_idx].radio;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001123 tx_power.s.dsp_predis_atten[c] =
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001124 gain_table[band][power_idx].dsp;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001125
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001126 D_TXPOWER("chain %d mimo %d idx %d "
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001127 "gain 0x%02x dsp %d\n",
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001128 c, atten_value, power_idx,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001129 tx_power.s.radio_tx_gain[c],
1130 tx_power.s.dsp_predis_atten[c]);
1131 } /* for each chain */
1132
1133 tx_power_tbl->power_tbl[i].dw = cpu_to_le32(tx_power.dw);
1134
1135 } /* for each rate */
1136
1137 return 0;
1138}
1139
1140/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001141 * il4965_send_tx_power - Configure the TXPOWER level user limit
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001142 *
1143 * Uses the active RXON for channel, band, and characteristics (ht40, high)
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001144 * The power limit is taken from il->tx_power_user_lmt.
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001145 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001146static int il4965_send_tx_power(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001147{
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001148 struct il4965_txpowertable_cmd cmd = { 0 };
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001149 int ret;
1150 u8 band = 0;
1151 bool is_ht40 = false;
1152 u8 ctrl_chan_high = 0;
Stanislaw Gruszka7c2cde22011-11-15 11:29:04 +01001153 struct il_rxon_context *ctx = &il->ctx;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001154
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001155 if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &il->status),
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001156 "TX Power requested while scanning!\n"))
1157 return -EAGAIN;
1158
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001159 band = il->band == IEEE80211_BAND_2GHZ;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001160
Wey-Yi Guybe663ab2011-02-21 11:27:26 -08001161 is_ht40 = iw4965_is_ht40_channel(ctx->active.flags);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001162
1163 if (is_ht40 && (ctx->active.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
1164 ctrl_chan_high = 1;
1165
1166 cmd.band = band;
1167 cmd.channel = ctx->active.channel;
1168
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001169 ret = il4965_fill_txpower_tbl(il, band,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001170 le16_to_cpu(ctx->active.channel),
1171 is_ht40, ctrl_chan_high, &cmd.tx_power);
1172 if (ret)
1173 goto out;
1174
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001175 ret = il_send_cmd_pdu(il,
Stanislaw Gruszka3b98c7f2011-08-26 16:29:35 +02001176 REPLY_TX_PWR_TBL_CMD, sizeof(cmd), &cmd);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001177
1178out:
1179 return ret;
1180}
1181
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001182static int il4965_send_rxon_assoc(struct il_priv *il,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001183 struct il_rxon_context *ctx)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001184{
1185 int ret = 0;
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001186 struct il4965_rxon_assoc_cmd rxon_assoc;
1187 const struct il_rxon_cmd *rxon1 = &ctx->staging;
1188 const struct il_rxon_cmd *rxon2 = &ctx->active;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001189
Stanislaw Gruszka232913b2011-08-26 10:45:16 +02001190 if (rxon1->flags == rxon2->flags &&
1191 rxon1->filter_flags == rxon2->filter_flags &&
1192 rxon1->cck_basic_rates == rxon2->cck_basic_rates &&
1193 rxon1->ofdm_ht_single_stream_basic_rates ==
1194 rxon2->ofdm_ht_single_stream_basic_rates &&
1195 rxon1->ofdm_ht_dual_stream_basic_rates ==
1196 rxon2->ofdm_ht_dual_stream_basic_rates &&
1197 rxon1->rx_chain == rxon2->rx_chain &&
1198 rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates) {
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001199 D_INFO("Using current RXON_ASSOC. Not resending.\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001200 return 0;
1201 }
1202
1203 rxon_assoc.flags = ctx->staging.flags;
1204 rxon_assoc.filter_flags = ctx->staging.filter_flags;
1205 rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
1206 rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
1207 rxon_assoc.reserved = 0;
1208 rxon_assoc.ofdm_ht_single_stream_basic_rates =
1209 ctx->staging.ofdm_ht_single_stream_basic_rates;
1210 rxon_assoc.ofdm_ht_dual_stream_basic_rates =
1211 ctx->staging.ofdm_ht_dual_stream_basic_rates;
1212 rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
1213
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001214 ret = il_send_cmd_pdu_async(il, REPLY_RXON_ASSOC,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001215 sizeof(rxon_assoc), &rxon_assoc, NULL);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001216
1217 return ret;
1218}
1219
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001220static int il4965_commit_rxon(struct il_priv *il, struct il_rxon_context *ctx)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001221{
1222 /* cast away the const for active_rxon in this function */
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001223 struct il_rxon_cmd *active_rxon = (void *)&ctx->active;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001224 int ret;
1225 bool new_assoc =
1226 !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
1227
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001228 if (!il_is_alive(il))
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001229 return -EBUSY;
1230
1231 if (!ctx->is_active)
1232 return 0;
1233
1234 /* always get timestamp with Rx frame */
1235 ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
1236
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001237 ret = il_check_rxon_cmd(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001238 if (ret) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001239 IL_ERR("Invalid RXON configuration. Not committing.\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001240 return -EINVAL;
1241 }
1242
1243 /*
1244 * receive commit_rxon request
1245 * abort any previous channel switch if still in process
1246 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001247 if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &il->status) &&
Stanislaw Gruszka232913b2011-08-26 10:45:16 +02001248 il->switch_channel != ctx->staging.channel) {
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001249 D_11H("abort channel switch on %d\n",
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001250 le16_to_cpu(il->switch_channel));
1251 il_chswitch_done(il, false);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001252 }
1253
1254 /* If we don't need to send a full RXON, we can use
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001255 * il_rxon_assoc_cmd which is used to reconfigure filter
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001256 * and other flags for the current radio configuration. */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001257 if (!il_full_rxon_required(il, ctx)) {
1258 ret = il_send_rxon_assoc(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001259 if (ret) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001260 IL_ERR("Error setting RXON_ASSOC (%d)\n", ret);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001261 return ret;
1262 }
1263
1264 memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001265 il_print_rx_config_cmd(il, ctx);
Stanislaw Gruszka17e859a2011-07-27 15:37:43 +02001266 /*
1267 * We do not commit tx power settings while channel changing,
1268 * do it now if tx power changed.
1269 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001270 il_set_tx_power(il, il->tx_power_next, false);
Stanislaw Gruszka17e859a2011-07-27 15:37:43 +02001271 return 0;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001272 }
1273
1274 /* If we are currently associated and the new config requires
1275 * an RXON_ASSOC and the new config wants the associated mask enabled,
1276 * we must clear the associated from the active configuration
1277 * before we apply the new config */
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001278 if (il_is_associated_ctx(ctx) && new_assoc) {
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001279 D_INFO("Toggling associated bit on current RXON\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001280 active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
1281
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001282 ret = il_send_cmd_pdu(il, ctx->rxon_cmd,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001283 sizeof(struct il_rxon_cmd),
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001284 active_rxon);
1285
1286 /* If the mask clearing failed then we set
1287 * active_rxon back to what it was previously */
1288 if (ret) {
1289 active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001290 IL_ERR("Error clearing ASSOC_MSK (%d)\n", ret);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001291 return ret;
1292 }
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001293 il_clear_ucode_stations(il, ctx);
1294 il_restore_stations(il, ctx);
1295 ret = il4965_restore_default_wep_keys(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001296 if (ret) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001297 IL_ERR("Failed to restore WEP keys (%d)\n", ret);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001298 return ret;
1299 }
1300 }
1301
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001302 D_INFO("Sending RXON\n"
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001303 "* with%s RXON_FILTER_ASSOC_MSK\n"
1304 "* channel = %d\n"
1305 "* bssid = %pM\n",
1306 (new_assoc ? "" : "out"),
1307 le16_to_cpu(ctx->staging.channel),
1308 ctx->staging.bssid_addr);
1309
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001310 il_set_rxon_hwcrypto(il, ctx,
1311 !il->cfg->mod_params->sw_crypto);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001312
1313 /* Apply the new configuration
1314 * RXON unassoc clears the station table in uCode so restoration of
1315 * stations is needed after it (the RXON command) completes
1316 */
1317 if (!new_assoc) {
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001318 ret = il_send_cmd_pdu(il, ctx->rxon_cmd,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001319 sizeof(struct il_rxon_cmd), &ctx->staging);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001320 if (ret) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001321 IL_ERR("Error setting new RXON (%d)\n", ret);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001322 return ret;
1323 }
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001324 D_INFO("Return from !new_assoc RXON.\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001325 memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001326 il_clear_ucode_stations(il, ctx);
1327 il_restore_stations(il, ctx);
1328 ret = il4965_restore_default_wep_keys(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001329 if (ret) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001330 IL_ERR("Failed to restore WEP keys (%d)\n", ret);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001331 return ret;
1332 }
1333 }
1334 if (new_assoc) {
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001335 il->start_calib = 0;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001336 /* Apply the new configuration
1337 * RXON assoc doesn't clear the station table in uCode,
1338 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001339 ret = il_send_cmd_pdu(il, ctx->rxon_cmd,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001340 sizeof(struct il_rxon_cmd), &ctx->staging);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001341 if (ret) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001342 IL_ERR("Error setting new RXON (%d)\n", ret);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001343 return ret;
1344 }
1345 memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
1346 }
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001347 il_print_rx_config_cmd(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001348
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001349 il4965_init_sensitivity(il);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001350
1351 /* If we issue a new RXON command which required a tune then we must
1352 * send a new TXPOWER command or we won't be able to Tx any frames */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001353 ret = il_set_tx_power(il, il->tx_power_next, true);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001354 if (ret) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001355 IL_ERR("Error sending TX power (%d)\n", ret);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001356 return ret;
1357 }
1358
1359 return 0;
1360}
1361
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001362static int il4965_hw_channel_switch(struct il_priv *il,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001363 struct ieee80211_channel_switch *ch_switch)
1364{
Stanislaw Gruszka7c2cde22011-11-15 11:29:04 +01001365 struct il_rxon_context *ctx = &il->ctx;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001366 int rc;
1367 u8 band = 0;
1368 bool is_ht40 = false;
1369 u8 ctrl_chan_high = 0;
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001370 struct il4965_channel_switch_cmd cmd;
1371 const struct il_channel_info *ch_info;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001372 u32 switch_time_in_usec, ucode_switch_time;
1373 u16 ch;
1374 u32 tsf_low;
1375 u8 switch_count;
1376 u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
1377 struct ieee80211_vif *vif = ctx->vif;
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001378 band = il->band == IEEE80211_BAND_2GHZ;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001379
Wey-Yi Guybe663ab2011-02-21 11:27:26 -08001380 is_ht40 = iw4965_is_ht40_channel(ctx->staging.flags);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001381
1382 if (is_ht40 &&
1383 (ctx->staging.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
1384 ctrl_chan_high = 1;
1385
1386 cmd.band = band;
1387 cmd.expect_beacon = 0;
1388 ch = ch_switch->channel->hw_value;
1389 cmd.channel = cpu_to_le16(ch);
1390 cmd.rxon_flags = ctx->staging.flags;
1391 cmd.rxon_filter_flags = ctx->staging.filter_flags;
1392 switch_count = ch_switch->count;
1393 tsf_low = ch_switch->timestamp & 0x0ffffffff;
1394 /*
1395 * calculate the ucode channel switch time
1396 * adding TSF as one of the factor for when to switch
1397 */
Stanislaw Gruszka232913b2011-08-26 10:45:16 +02001398 if (il->ucode_beacon_time > tsf_low && beacon_interval) {
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001399 if (switch_count > ((il->ucode_beacon_time - tsf_low) /
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001400 beacon_interval)) {
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001401 switch_count -= (il->ucode_beacon_time -
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001402 tsf_low) / beacon_interval;
1403 } else
1404 switch_count = 0;
1405 }
1406 if (switch_count <= 1)
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001407 cmd.switch_time = cpu_to_le32(il->ucode_beacon_time);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001408 else {
1409 switch_time_in_usec =
1410 vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001411 ucode_switch_time = il_usecs_to_beacons(il,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001412 switch_time_in_usec,
1413 beacon_interval);
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001414 cmd.switch_time = il_add_beacon_time(il,
1415 il->ucode_beacon_time,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001416 ucode_switch_time,
1417 beacon_interval);
1418 }
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001419 D_11H("uCode time for the switch is 0x%x\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001420 cmd.switch_time);
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001421 ch_info = il_get_channel_info(il, il->band, ch);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001422 if (ch_info)
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001423 cmd.expect_beacon = il_is_channel_radar(ch_info);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001424 else {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001425 IL_ERR("invalid channel switch from %u to %u\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001426 ctx->active.channel, ch);
1427 return -EFAULT;
1428 }
1429
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001430 rc = il4965_fill_txpower_tbl(il, band, ch, is_ht40,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001431 ctrl_chan_high, &cmd.tx_power);
1432 if (rc) {
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001433 D_11H("error:%d fill txpower_tbl\n", rc);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001434 return rc;
1435 }
1436
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001437 return il_send_cmd_pdu(il,
Wey-Yi Guybe663ab2011-02-21 11:27:26 -08001438 REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001439}
1440
1441/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001442 * il4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001443 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001444static void il4965_txq_update_byte_cnt_tbl(struct il_priv *il,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001445 struct il_tx_queue *txq,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001446 u16 byte_cnt)
1447{
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001448 struct il4965_scd_bc_tbl *scd_bc_tbl = il->scd_bc_tbls.addr;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001449 int txq_id = txq->q.id;
1450 int write_ptr = txq->q.write_ptr;
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001451 int len = byte_cnt + IL_TX_CRC_SIZE + IL_TX_DELIMITER_SIZE;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001452 __le16 bc_ent;
1453
1454 WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
1455
1456 bc_ent = cpu_to_le16(len & 0xFFF);
1457 /* Set up byte count within first 256 entries */
1458 scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
1459
1460 /* If within first 64 entries, duplicate at end */
1461 if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
1462 scd_bc_tbl[txq_id].
1463 tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
1464}
1465
1466/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001467 * il4965_hw_get_temperature - return the calibrated temperature (in Kelvin)
Stanislaw Gruszkaebf0d902011-08-26 15:43:47 +02001468 * @stats: Provides the temperature reading from the uCode
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001469 *
Stanislaw Gruszkaebf0d902011-08-26 15:43:47 +02001470 * A return of <0 indicates bogus data in the stats
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001471 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001472static int il4965_hw_get_temperature(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001473{
1474 s32 temperature;
1475 s32 vt;
1476 s32 R1, R2, R3;
1477 u32 R4;
1478
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001479 if (test_bit(STATUS_TEMPERATURE, &il->status) &&
Stanislaw Gruszkaebf0d902011-08-26 15:43:47 +02001480 (il->_4965.stats.flag &
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001481 STATISTICS_REPLY_FLG_HT40_MODE_MSK)) {
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001482 D_TEMP("Running HT40 temperature calibration\n");
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001483 R1 = (s32)le32_to_cpu(il->card_alive_init.therm_r1[1]);
1484 R2 = (s32)le32_to_cpu(il->card_alive_init.therm_r2[1]);
1485 R3 = (s32)le32_to_cpu(il->card_alive_init.therm_r3[1]);
1486 R4 = le32_to_cpu(il->card_alive_init.therm_r4[1]);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001487 } else {
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001488 D_TEMP("Running temperature calibration\n");
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001489 R1 = (s32)le32_to_cpu(il->card_alive_init.therm_r1[0]);
1490 R2 = (s32)le32_to_cpu(il->card_alive_init.therm_r2[0]);
1491 R3 = (s32)le32_to_cpu(il->card_alive_init.therm_r3[0]);
1492 R4 = le32_to_cpu(il->card_alive_init.therm_r4[0]);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001493 }
1494
1495 /*
1496 * Temperature is only 23 bits, so sign extend out to 32.
1497 *
Stanislaw Gruszkaebf0d902011-08-26 15:43:47 +02001498 * NOTE If we haven't received a stats notification yet
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001499 * with an updated temperature, use R4 provided to us in the
1500 * "initialize" ALIVE response.
1501 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001502 if (!test_bit(STATUS_TEMPERATURE, &il->status))
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001503 vt = sign_extend32(R4, 23);
1504 else
Stanislaw Gruszkaebf0d902011-08-26 15:43:47 +02001505 vt = sign_extend32(le32_to_cpu(il->_4965.stats.
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001506 general.common.temperature), 23);
1507
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001508 D_TEMP("Calib values R[1-3]: %d %d %d R4: %d\n", R1, R2, R3, vt);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001509
1510 if (R3 == R1) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001511 IL_ERR("Calibration conflict R1 == R3\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001512 return -1;
1513 }
1514
1515 /* Calculate temperature in degrees Kelvin, adjust by 97%.
1516 * Add offset to center the adjustment around 0 degrees Centigrade. */
1517 temperature = TEMPERATURE_CALIB_A_VAL * (vt - R2);
1518 temperature /= (R3 - R1);
1519 temperature = (temperature * 97) / 100 + TEMPERATURE_CALIB_KELVIN_OFFSET;
1520
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001521 D_TEMP("Calibrated temperature: %dK, %dC\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001522 temperature, KELVIN_TO_CELSIUS(temperature));
1523
1524 return temperature;
1525}
1526
1527/* Adjust Txpower only if temperature variance is greater than threshold. */
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001528#define IL_TEMPERATURE_THRESHOLD 3
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001529
1530/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001531 * il4965_is_temp_calib_needed - determines if new calibration is needed
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001532 *
1533 * If the temperature changed has changed sufficiently, then a recalibration
1534 * is needed.
1535 *
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001536 * Assumes caller will replace il->last_temperature once calibration
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001537 * executed.
1538 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001539static int il4965_is_temp_calib_needed(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001540{
1541 int temp_diff;
1542
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001543 if (!test_bit(STATUS_STATISTICS, &il->status)) {
Stanislaw Gruszkaebf0d902011-08-26 15:43:47 +02001544 D_TEMP("Temperature not updated -- no stats.\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001545 return 0;
1546 }
1547
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001548 temp_diff = il->temperature - il->last_temperature;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001549
1550 /* get absolute value */
1551 if (temp_diff < 0) {
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001552 D_POWER("Getting cooler, delta %d\n", temp_diff);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001553 temp_diff = -temp_diff;
1554 } else if (temp_diff == 0)
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001555 D_POWER("Temperature unchanged\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001556 else
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001557 D_POWER("Getting warmer, delta %d\n", temp_diff);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001558
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001559 if (temp_diff < IL_TEMPERATURE_THRESHOLD) {
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001560 D_POWER(" => thermal txpower calib not needed\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001561 return 0;
1562 }
1563
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001564 D_POWER(" => thermal txpower calib needed\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001565
1566 return 1;
1567}
1568
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001569static void il4965_temperature_calib(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001570{
1571 s32 temp;
1572
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001573 temp = il4965_hw_get_temperature(il);
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001574 if (IL_TX_POWER_TEMPERATURE_OUT_OF_RANGE(temp))
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001575 return;
1576
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001577 if (il->temperature != temp) {
1578 if (il->temperature)
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001579 D_TEMP("Temperature changed "
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001580 "from %dC to %dC\n",
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001581 KELVIN_TO_CELSIUS(il->temperature),
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001582 KELVIN_TO_CELSIUS(temp));
1583 else
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001584 D_TEMP("Temperature "
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001585 "initialized to %dC\n",
1586 KELVIN_TO_CELSIUS(temp));
1587 }
1588
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001589 il->temperature = temp;
1590 set_bit(STATUS_TEMPERATURE, &il->status);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001591
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001592 if (!il->disable_tx_power_cal &&
1593 unlikely(!test_bit(STATUS_SCANNING, &il->status)) &&
1594 il4965_is_temp_calib_needed(il))
1595 queue_work(il->workqueue, &il->txpower_work);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001596}
1597
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001598static u16 il4965_get_hcmd_size(u8 cmd_id, u16 len)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001599{
1600 switch (cmd_id) {
1601 case REPLY_RXON:
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001602 return (u16) sizeof(struct il4965_rxon_cmd);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001603 default:
1604 return len;
1605 }
1606}
1607
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001608static u16 il4965_build_addsta_hcmd(const struct il_addsta_cmd *cmd,
Wey-Yi Guybe663ab2011-02-21 11:27:26 -08001609 u8 *data)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001610{
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001611 struct il4965_addsta_cmd *addsta = (struct il4965_addsta_cmd *)data;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001612 addsta->mode = cmd->mode;
1613 memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify));
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001614 memcpy(&addsta->key, &cmd->key, sizeof(struct il4965_keyinfo));
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001615 addsta->station_flags = cmd->station_flags;
1616 addsta->station_flags_msk = cmd->station_flags_msk;
1617 addsta->tid_disable_tx = cmd->tid_disable_tx;
1618 addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid;
1619 addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid;
1620 addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn;
1621 addsta->sleep_tx_count = cmd->sleep_tx_count;
1622 addsta->reserved1 = cpu_to_le16(0);
1623 addsta->reserved2 = cpu_to_le16(0);
1624
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001625 return (u16)sizeof(struct il4965_addsta_cmd);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001626}
1627
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001628static inline u32 il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001629{
1630 return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN;
1631}
1632
1633/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001634 * il4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001635 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001636static int il4965_tx_status_reply_tx(struct il_priv *il,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001637 struct il_ht_agg *agg,
1638 struct il4965_tx_resp *tx_resp,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001639 int txq_id, u16 start_idx)
1640{
1641 u16 status;
1642 struct agg_tx_status *frame_status = tx_resp->u.agg_status;
1643 struct ieee80211_tx_info *info = NULL;
1644 struct ieee80211_hdr *hdr = NULL;
1645 u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
1646 int i, sh, idx;
1647 u16 seq;
1648 if (agg->wait_for_ba)
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001649 D_TX_REPLY("got tx response w/o block-ack\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001650
1651 agg->frame_count = tx_resp->frame_count;
1652 agg->start_idx = start_idx;
1653 agg->rate_n_flags = rate_n_flags;
1654 agg->bitmap = 0;
1655
1656 /* num frames attempted by Tx command */
1657 if (agg->frame_count == 1) {
1658 /* Only one frame was attempted; no block-ack will arrive */
1659 status = le16_to_cpu(frame_status[0].status);
1660 idx = start_idx;
1661
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001662 D_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001663 agg->frame_count, agg->start_idx, idx);
1664
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001665 info = IEEE80211_SKB_CB(il->txq[txq_id].txb[idx].skb);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001666 info->status.rates[0].count = tx_resp->failure_frame + 1;
1667 info->flags &= ~IEEE80211_TX_CTL_AMPDU;
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001668 info->flags |= il4965_tx_status_to_mac80211(status);
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001669 il4965_hwrate_to_tx_control(il, rate_n_flags, info);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001670
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001671 D_TX_REPLY("1 Frame 0x%x failure :%d\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001672 status & 0xff, tx_resp->failure_frame);
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001673 D_TX_REPLY("Rate Info rate_n_flags=%x\n", rate_n_flags);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001674
1675 agg->wait_for_ba = 0;
1676 } else {
1677 /* Two or more frames were attempted; expect block-ack */
1678 u64 bitmap = 0;
1679 int start = agg->start_idx;
1680
Stanislaw Gruszka6ce1dc42011-08-26 15:49:28 +02001681 /* Construct bit-map of pending frames within Tx win */
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001682 for (i = 0; i < agg->frame_count; i++) {
1683 u16 sc;
1684 status = le16_to_cpu(frame_status[i].status);
1685 seq = le16_to_cpu(frame_status[i].sequence);
Stanislaw Gruszka2d09b062011-08-26 16:10:40 +02001686 idx = SEQ_TO_IDX(seq);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001687 txq_id = SEQ_TO_QUEUE(seq);
1688
1689 if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
1690 AGG_TX_STATE_ABORT_MSK))
1691 continue;
1692
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001693 D_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001694 agg->frame_count, txq_id, idx);
1695
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001696 hdr = il_tx_queue_get_hdr(il, txq_id, idx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001697 if (!hdr) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001698 IL_ERR(
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001699 "BUG_ON idx doesn't point to valid skb"
1700 " idx=%d, txq_id=%d\n", idx, txq_id);
1701 return -1;
1702 }
1703
1704 sc = le16_to_cpu(hdr->seq_ctrl);
1705 if (idx != (SEQ_TO_SN(sc) & 0xff)) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001706 IL_ERR(
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001707 "BUG_ON idx doesn't match seq control"
1708 " idx=%d, seq_idx=%d, seq=%d\n",
1709 idx, SEQ_TO_SN(sc), hdr->seq_ctrl);
1710 return -1;
1711 }
1712
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001713 D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001714 i, idx, SEQ_TO_SN(sc));
1715
1716 sh = idx - start;
1717 if (sh > 64) {
1718 sh = (start - idx) + 0xff;
1719 bitmap = bitmap << sh;
1720 sh = 0;
1721 start = idx;
1722 } else if (sh < -64)
1723 sh = 0xff - (start - idx);
1724 else if (sh < 0) {
1725 sh = start - idx;
1726 start = idx;
1727 bitmap = bitmap << sh;
1728 sh = 0;
1729 }
1730 bitmap |= 1ULL << sh;
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001731 D_TX_REPLY("start=%d bitmap=0x%llx\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001732 start, (unsigned long long)bitmap);
1733 }
1734
1735 agg->bitmap = bitmap;
1736 agg->start_idx = start;
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001737 D_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001738 agg->frame_count, agg->start_idx,
1739 (unsigned long long)agg->bitmap);
1740
1741 if (bitmap)
1742 agg->wait_for_ba = 1;
1743 }
1744 return 0;
1745}
1746
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001747static u8 il4965_find_station(struct il_priv *il, const u8 *addr)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001748{
1749 int i;
1750 int start = 0;
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001751 int ret = IL_INVALID_STATION;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001752 unsigned long flags;
1753
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001754 if ((il->iw_mode == NL80211_IFTYPE_ADHOC))
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001755 start = IL_STA_ID;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001756
1757 if (is_broadcast_ether_addr(addr))
Stanislaw Gruszka7c2cde22011-11-15 11:29:04 +01001758 return il->ctx.bcast_sta_id;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001759
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001760 spin_lock_irqsave(&il->sta_lock, flags);
1761 for (i = start; i < il->hw_params.max_stations; i++)
1762 if (il->stations[i].used &&
1763 (!compare_ether_addr(il->stations[i].sta.sta.addr,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001764 addr))) {
1765 ret = i;
1766 goto out;
1767 }
1768
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001769 D_ASSOC("can not find STA %pM total %d\n",
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001770 addr, il->num_stations);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001771
1772 out:
1773 /*
1774 * It may be possible that more commands interacting with stations
1775 * arrive before we completed processing the adding of
1776 * station
1777 */
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001778 if (ret != IL_INVALID_STATION &&
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001779 (!(il->stations[ret].used & IL_STA_UCODE_ACTIVE) ||
1780 ((il->stations[ret].used & IL_STA_UCODE_ACTIVE) &&
1781 (il->stations[ret].used & IL_STA_UCODE_INPROGRESS)))) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001782 IL_ERR("Requested station info for sta %d before ready.\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001783 ret);
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001784 ret = IL_INVALID_STATION;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001785 }
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001786 spin_unlock_irqrestore(&il->sta_lock, flags);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001787 return ret;
1788}
1789
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001790static int il4965_get_ra_sta_id(struct il_priv *il, struct ieee80211_hdr *hdr)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001791{
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001792 if (il->iw_mode == NL80211_IFTYPE_STATION) {
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001793 return IL_AP_ID;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001794 } else {
1795 u8 *da = ieee80211_get_DA(hdr);
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001796 return il4965_find_station(il, da);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001797 }
1798}
1799
1800/**
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001801 * il4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001802 */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001803static void il4965_rx_reply_tx(struct il_priv *il,
Stanislaw Gruszkab73bb5f2011-08-26 14:37:54 +02001804 struct il_rx_buf *rxb)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001805{
Stanislaw Gruszkadcae1c62011-08-26 14:36:21 +02001806 struct il_rx_pkt *pkt = rxb_addr(rxb);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001807 u16 sequence = le16_to_cpu(pkt->hdr.sequence);
1808 int txq_id = SEQ_TO_QUEUE(sequence);
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001809 int idx = SEQ_TO_IDX(sequence);
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001810 struct il_tx_queue *txq = &il->txq[txq_id];
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001811 struct ieee80211_hdr *hdr;
1812 struct ieee80211_tx_info *info;
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001813 struct il4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001814 u32 status = le32_to_cpu(tx_resp->u.status);
1815 int uninitialized_var(tid);
1816 int sta_id;
1817 int freed;
1818 u8 *qc = NULL;
1819 unsigned long flags;
1820
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001821 if (idx >= txq->q.n_bd || il_queue_used(&txq->q, idx) == 0) {
1822 IL_ERR("Read idx for DMA queue txq_id (%d) idx %d "
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001823 "is out of range [0-%d] %d %d\n", txq_id,
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001824 idx, txq->q.n_bd, txq->q.write_ptr,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001825 txq->q.read_ptr);
1826 return;
1827 }
1828
1829 txq->time_stamp = jiffies;
1830 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
1831 memset(&info->status, 0, sizeof(info->status));
1832
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001833 hdr = il_tx_queue_get_hdr(il, txq_id, idx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001834 if (ieee80211_is_data_qos(hdr->frame_control)) {
1835 qc = ieee80211_get_qos_ctl(hdr);
1836 tid = qc[0] & 0xf;
1837 }
1838
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001839 sta_id = il4965_get_ra_sta_id(il, hdr);
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001840 if (txq->sched_retry && unlikely(sta_id == IL_INVALID_STATION)) {
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001841 IL_ERR("Station not known\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001842 return;
1843 }
1844
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001845 spin_lock_irqsave(&il->sta_lock, flags);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001846 if (txq->sched_retry) {
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001847 const u32 scd_ssn = il4965_get_scd_ssn(tx_resp);
1848 struct il_ht_agg *agg = NULL;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001849 WARN_ON(!qc);
1850
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001851 agg = &il->stations[sta_id].tid[tid].agg;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001852
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001853 il4965_tx_status_reply_tx(il, agg, tx_resp, txq_id, idx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001854
1855 /* check if BAR is needed */
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001856 if ((tx_resp->frame_count == 1) && !il4965_is_tx_success(status))
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001857 info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
1858
1859 if (txq->q.read_ptr != (scd_ssn & 0xff)) {
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001860 idx = il_queue_dec_wrap(scd_ssn & 0xff,
Wey-Yi Guybe663ab2011-02-21 11:27:26 -08001861 txq->q.n_bd);
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001862 D_TX_REPLY("Retry scheduler reclaim scd_ssn "
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001863 "%d idx %d\n", scd_ssn , idx);
1864 freed = il4965_tx_queue_reclaim(il, txq_id, idx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001865 if (qc)
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001866 il4965_free_tfds_in_queue(il, sta_id,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001867 tid, freed);
1868
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001869 if (il->mac80211_registered &&
Stanislaw Gruszka232913b2011-08-26 10:45:16 +02001870 il_queue_space(&txq->q) > txq->q.low_mark &&
1871 agg->state != IL_EMPTYING_HW_QUEUE_DELBA)
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001872 il_wake_queue(il, txq);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001873 }
1874 } else {
1875 info->status.rates[0].count = tx_resp->failure_frame + 1;
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001876 info->flags |= il4965_tx_status_to_mac80211(status);
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001877 il4965_hwrate_to_tx_control(il,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001878 le32_to_cpu(tx_resp->rate_n_flags),
1879 info);
1880
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001881 D_TX_REPLY("TXQ %d status %s (0x%08x) "
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001882 "rate_n_flags 0x%x retries %d\n",
1883 txq_id,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001884 il4965_get_tx_fail_reason(status), status,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001885 le32_to_cpu(tx_resp->rate_n_flags),
1886 tx_resp->failure_frame);
1887
Stanislaw Gruszka0c2c8852011-11-15 12:30:17 +01001888 freed = il4965_tx_queue_reclaim(il, txq_id, idx);
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001889 if (qc && likely(sta_id != IL_INVALID_STATION))
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001890 il4965_free_tfds_in_queue(il, sta_id, tid, freed);
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001891 else if (sta_id == IL_INVALID_STATION)
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001892 D_TX_REPLY("Station not known\n");
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001893
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001894 if (il->mac80211_registered &&
Stanislaw Gruszka232913b2011-08-26 10:45:16 +02001895 il_queue_space(&txq->q) > txq->q.low_mark)
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001896 il_wake_queue(il, txq);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001897 }
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001898 if (qc && likely(sta_id != IL_INVALID_STATION))
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001899 il4965_txq_check_empty(il, sta_id, tid, txq_id);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001900
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001901 il4965_check_abort_status(il, tx_resp->frame_count, status);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001902
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001903 spin_unlock_irqrestore(&il->sta_lock, flags);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001904}
1905
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001906static void il4965_rx_beacon_notif(struct il_priv *il,
Stanislaw Gruszkab73bb5f2011-08-26 14:37:54 +02001907 struct il_rx_buf *rxb)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001908{
Stanislaw Gruszkadcae1c62011-08-26 14:36:21 +02001909 struct il_rx_pkt *pkt = rxb_addr(rxb);
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001910 struct il4965_beacon_notif *beacon = (void *)pkt->u.raw;
Wey-Yi Guybe663ab2011-02-21 11:27:26 -08001911 u8 rate __maybe_unused =
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001912 il4965_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001913
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001914 D_RX("beacon status %#x, retries:%d ibssmgr:%d "
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001915 "tsf:0x%.8x%.8x rate:%d\n",
1916 le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK,
1917 beacon->beacon_notify_hdr.failure_frame,
1918 le32_to_cpu(beacon->ibss_mgr_status),
1919 le32_to_cpu(beacon->high_tsf),
1920 le32_to_cpu(beacon->low_tsf), rate);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001921
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001922 il->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001923}
1924
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001925/* Set up 4965-specific Rx frame reply handlers */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001926static void il4965_rx_handler_setup(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001927{
1928 /* Legacy Rx frames */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001929 il->rx_handlers[REPLY_RX] = il4965_rx_reply_rx;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001930 /* Tx response */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001931 il->rx_handlers[REPLY_TX] = il4965_rx_reply_tx;
1932 il->rx_handlers[BEACON_NOTIFICATION] = il4965_rx_beacon_notif;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001933}
1934
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02001935static struct il_hcmd_ops il4965_hcmd = {
1936 .rxon_assoc = il4965_send_rxon_assoc,
1937 .commit_rxon = il4965_commit_rxon,
1938 .set_rxon_chain = il4965_set_rxon_chain,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001939};
1940
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001941static void il4965_post_scan(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001942{
Stanislaw Gruszka7c2cde22011-11-15 11:29:04 +01001943 struct il_rxon_context *ctx = &il->ctx;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001944
1945 /*
1946 * Since setting the RXON may have been deferred while
1947 * performing the scan, fire one off if needed
1948 */
1949 if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001950 il_commit_rxon(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001951}
1952
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001953static void il4965_post_associate(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001954{
Stanislaw Gruszka7c2cde22011-11-15 11:29:04 +01001955 struct il_rxon_context *ctx = &il->ctx;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001956 struct ieee80211_vif *vif = ctx->vif;
1957 struct ieee80211_conf *conf = NULL;
1958 int ret = 0;
1959
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001960 if (!vif || !il->is_open)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001961 return;
1962
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001963 if (test_bit(STATUS_EXIT_PENDING, &il->status))
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001964 return;
1965
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001966 il_scan_cancel_timeout(il, 200);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001967
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001968 conf = il_ieee80211_get_hw_conf(il->hw);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001969
1970 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001971 il_commit_rxon(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001972
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001973 ret = il_send_rxon_timing(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001974 if (ret)
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02001975 IL_WARN("RXON timing - "
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001976 "Attempting to continue.\n");
1977
1978 ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
1979
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001980 il_set_rxon_ht(il, &il->current_ht_config);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001981
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02001982 if (il->cfg->ops->hcmd->set_rxon_chain)
1983 il->cfg->ops->hcmd->set_rxon_chain(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001984
1985 ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
1986
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01001987 D_ASSOC("assoc id %d beacon interval %d\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08001988 vif->bss_conf.aid, vif->bss_conf.beacon_int);
1989
1990 if (vif->bss_conf.use_short_preamble)
1991 ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
1992 else
1993 ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
1994
1995 if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
1996 if (vif->bss_conf.use_short_slot)
1997 ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
1998 else
1999 ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
2000 }
2001
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002002 il_commit_rxon(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002003
Stanislaw Gruszka58de00a2011-11-15 11:21:01 +01002004 D_ASSOC("Associated as %d to: %pM\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002005 vif->bss_conf.aid, ctx->active.bssid_addr);
2006
2007 switch (vif->type) {
2008 case NL80211_IFTYPE_STATION:
2009 break;
2010 case NL80211_IFTYPE_ADHOC:
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002011 il4965_send_beacon_cmd(il);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002012 break;
2013 default:
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02002014 IL_ERR("%s Should not be called in %d mode\n",
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002015 __func__, vif->type);
2016 break;
2017 }
2018
2019 /* the chain noise calibration will enabled PM upon completion
2020 * If chain noise has already been run, then we need to enable
2021 * power management here */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002022 if (il->chain_noise_data.state == IL_CHAIN_NOISE_DONE)
2023 il_power_update_mode(il, false);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002024
2025 /* Enable Rx differential gain and sensitivity calibrations */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002026 il4965_chain_noise_reset(il);
2027 il->start_calib = 1;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002028}
2029
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002030static void il4965_config_ap(struct il_priv *il)
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002031{
Stanislaw Gruszka7c2cde22011-11-15 11:29:04 +01002032 struct il_rxon_context *ctx = &il->ctx;
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002033 struct ieee80211_vif *vif = ctx->vif;
2034 int ret = 0;
2035
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002036 lockdep_assert_held(&il->mutex);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002037
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002038 if (test_bit(STATUS_EXIT_PENDING, &il->status))
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002039 return;
2040
2041 /* The following should be done only at AP bring up */
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002042 if (!il_is_associated_ctx(ctx)) {
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002043
2044 /* RXON - unassoc (to set timing command) */
2045 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002046 il_commit_rxon(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002047
2048 /* RXON Timing */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002049 ret = il_send_rxon_timing(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002050 if (ret)
Stanislaw Gruszka9406f792011-08-18 22:07:57 +02002051 IL_WARN("RXON timing failed - "
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002052 "Attempting to continue.\n");
2053
2054 /* AP has all antennas */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002055 il->chain_noise_data.active_chains =
2056 il->hw_params.valid_rx_ant;
2057 il_set_rxon_ht(il, &il->current_ht_config);
2058 if (il->cfg->ops->hcmd->set_rxon_chain)
2059 il->cfg->ops->hcmd->set_rxon_chain(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002060
2061 ctx->staging.assoc_id = 0;
2062
2063 if (vif->bss_conf.use_short_preamble)
2064 ctx->staging.flags |=
2065 RXON_FLG_SHORT_PREAMBLE_MSK;
2066 else
2067 ctx->staging.flags &=
2068 ~RXON_FLG_SHORT_PREAMBLE_MSK;
2069
2070 if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
2071 if (vif->bss_conf.use_short_slot)
2072 ctx->staging.flags |=
2073 RXON_FLG_SHORT_SLOT_MSK;
2074 else
2075 ctx->staging.flags &=
2076 ~RXON_FLG_SHORT_SLOT_MSK;
2077 }
2078 /* need to send beacon cmd before committing assoc RXON! */
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002079 il4965_send_beacon_cmd(il);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002080 /* restore RXON assoc */
2081 ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002082 il_commit_rxon(il, ctx);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002083 }
Stanislaw Gruszka46bc8d42011-10-24 16:49:25 +02002084 il4965_send_beacon_cmd(il);
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002085}
2086
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002087static struct il_hcmd_utils_ops il4965_hcmd_utils = {
2088 .get_hcmd_size = il4965_get_hcmd_size,
2089 .build_addsta_hcmd = il4965_build_addsta_hcmd,
2090 .request_scan = il4965_request_scan,
2091 .post_scan = il4965_post_scan,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002092};
2093
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002094static struct il_lib_ops il4965_lib = {
2095 .set_hw_params = il4965_hw_set_hw_params,
2096 .txq_update_byte_cnt_tbl = il4965_txq_update_byte_cnt_tbl,
2097 .txq_attach_buf_to_tfd = il4965_hw_txq_attach_buf_to_tfd,
2098 .txq_free_tfd = il4965_hw_txq_free_tfd,
2099 .txq_init = il4965_hw_tx_queue_init,
2100 .rx_handler_setup = il4965_rx_handler_setup,
2101 .is_valid_rtc_data_addr = il4965_hw_valid_rtc_data_addr,
2102 .init_alive_start = il4965_init_alive_start,
2103 .load_ucode = il4965_load_bsm,
2104 .dump_nic_error_log = il4965_dump_nic_error_log,
2105 .dump_fh = il4965_dump_fh,
2106 .set_channel_switch = il4965_hw_channel_switch,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002107 .apm_ops = {
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002108 .init = il_apm_init,
2109 .config = il4965_nic_config,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002110 },
2111 .eeprom_ops = {
2112 .regulatory_bands = {
2113 EEPROM_REGULATORY_BAND_1_CHANNELS,
2114 EEPROM_REGULATORY_BAND_2_CHANNELS,
2115 EEPROM_REGULATORY_BAND_3_CHANNELS,
2116 EEPROM_REGULATORY_BAND_4_CHANNELS,
2117 EEPROM_REGULATORY_BAND_5_CHANNELS,
2118 EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS,
2119 EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS
2120 },
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002121 .acquire_semaphore = il4965_eeprom_acquire_semaphore,
2122 .release_semaphore = il4965_eeprom_release_semaphore,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002123 },
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002124 .send_tx_power = il4965_send_tx_power,
2125 .update_chain_flags = il4965_update_chain_flags,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002126 .temp_ops = {
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002127 .temperature = il4965_temperature_calib,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002128 },
2129 .debugfs_ops = {
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002130 .rx_stats_read = il4965_ucode_rx_stats_read,
2131 .tx_stats_read = il4965_ucode_tx_stats_read,
2132 .general_stats_read = il4965_ucode_general_stats_read,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002133 },
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002134};
2135
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002136static const struct il_legacy_ops il4965_legacy_ops = {
2137 .post_associate = il4965_post_associate,
2138 .config_ap = il4965_config_ap,
2139 .manage_ibss_station = il4965_manage_ibss_station,
2140 .update_bcast_stations = il4965_update_bcast_stations,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002141};
2142
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002143struct ieee80211_ops il4965_hw_ops = {
2144 .tx = il4965_mac_tx,
2145 .start = il4965_mac_start,
2146 .stop = il4965_mac_stop,
2147 .add_interface = il_mac_add_interface,
2148 .remove_interface = il_mac_remove_interface,
2149 .change_interface = il_mac_change_interface,
2150 .config = il_mac_config,
2151 .configure_filter = il4965_configure_filter,
2152 .set_key = il4965_mac_set_key,
2153 .update_tkip_key = il4965_mac_update_tkip_key,
2154 .conf_tx = il_mac_conf_tx,
2155 .reset_tsf = il_mac_reset_tsf,
2156 .bss_info_changed = il_mac_bss_info_changed,
2157 .ampdu_action = il4965_mac_ampdu_action,
2158 .hw_scan = il_mac_hw_scan,
2159 .sta_add = il4965_mac_sta_add,
2160 .sta_remove = il_mac_sta_remove,
2161 .channel_switch = il4965_mac_channel_switch,
2162 .tx_last_beacon = il_mac_tx_last_beacon,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002163};
2164
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002165static const struct il_ops il4965_ops = {
2166 .lib = &il4965_lib,
2167 .hcmd = &il4965_hcmd,
2168 .utils = &il4965_hcmd_utils,
2169 .led = &il4965_led_ops,
2170 .legacy = &il4965_legacy_ops,
2171 .ieee80211_ops = &il4965_hw_ops,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002172};
2173
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002174static struct il_base_params il4965_base_params = {
Stanislaw Gruszkad3175162011-11-15 11:25:42 +01002175 .eeprom_size = IL4965_EEPROM_IMG_SIZE,
2176 .num_of_queues = IL49_NUM_QUEUES,
2177 .num_of_ampdu_queues = IL49_NUM_AMPDU_QUEUES,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002178 .pll_cfg_val = 0,
2179 .set_l0s = true,
2180 .use_bsm = true,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002181 .led_compensation = 61,
Stanislaw Gruszkad3175162011-11-15 11:25:42 +01002182 .chain_noise_num_beacons = IL4965_CAL_NUM_BEACONS,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002183 .wd_timeout = IL_DEF_WD_TIMEOUT,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002184 .temperature_kelvin = true,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002185 .ucode_tracing = true,
2186 .sensitivity_calib_by_driver = true,
2187 .chain_noise_calib_by_driver = true,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002188};
2189
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002190struct il_cfg il4965_cfg = {
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002191 .name = "Intel(R) Wireless WiFi Link 4965AGN",
Stanislaw Gruszkad3175162011-11-15 11:25:42 +01002192 .fw_name_pre = IL4965_FW_PRE,
2193 .ucode_api_max = IL4965_UCODE_API_MAX,
2194 .ucode_api_min = IL4965_UCODE_API_MIN,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002195 .sku = IL_SKU_A|IL_SKU_G|IL_SKU_N,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002196 .valid_tx_ant = ANT_AB,
2197 .valid_rx_ant = ANT_ABC,
2198 .eeprom_ver = EEPROM_4965_EEPROM_VERSION,
2199 .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
Stanislaw Gruszkae2ebc832011-10-24 15:41:30 +02002200 .ops = &il4965_ops,
2201 .mod_params = &il4965_mod_params,
2202 .base_params = &il4965_base_params,
2203 .led_mode = IL_LED_BLINK,
Wey-Yi Guy4bc85c12011-02-21 11:11:05 -08002204 /*
2205 * Force use of chains B and C for scan RX on 5 GHz band
2206 * because the device has off-channel reception on chain A.
2207 */
2208 .scan_rx_antennas[IEEE80211_BAND_5GHZ] = ANT_BC,
2209};
2210
2211/* Module firmware */
Stanislaw Gruszkad3175162011-11-15 11:25:42 +01002212MODULE_FIRMWARE(IL4965_MODULE_FIRMWARE(IL4965_UCODE_API_MAX));