iwl-5000.c revision c1adf9fb31e31ee753d613bd5bc6aef9b762b747
1/****************************************************************************** 2 * 3 * Copyright(c) 2007-2008 Intel Corporation. All rights reserved. 4 * 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 Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 23 * 24 *****************************************************************************/ 25 26#include <linux/kernel.h> 27#include <linux/module.h> 28#include <linux/version.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/skbuff.h> 34#include <linux/netdevice.h> 35#include <linux/wireless.h> 36#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" 45#include "iwl-5000-hw.h" 46 47#define IWL5000_UCODE_API "-1" 48 49static int iwl5000_apm_init(struct iwl_priv *priv) 50{ 51 int ret = 0; 52 53 iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, 54 CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); 55 56 iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); 57 58 /* set "initialization complete" bit to move adapter 59 * D0U* --> D0A* state */ 60 iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); 61 62 /* wait for clock stabilization */ 63 ret = iwl_poll_bit(priv, CSR_GP_CNTRL, 64 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 65 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); 66 if (ret < 0) { 67 IWL_DEBUG_INFO("Failed to init the card\n"); 68 return ret; 69 } 70 71 ret = iwl_grab_nic_access(priv); 72 if (ret) 73 return ret; 74 75 /* enable DMA */ 76 iwl_write_prph(priv, APMG_CLK_EN_REG, 77 APMG_CLK_VAL_DMA_CLK_RQT); 78 79 udelay(20); 80 81 iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, 82 APMG_PCIDEV_STT_VAL_L1_ACT_DIS); 83 84 iwl_release_nic_access(priv); 85 86 return ret; 87} 88 89static void iwl5000_nic_config(struct iwl_priv *priv) 90{ 91 unsigned long flags; 92 u16 radio_cfg; 93 u8 val_link; 94 95 spin_lock_irqsave(&priv->lock, flags); 96 97 pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); 98 99 /* disable L1 entry -- workaround for pre-B1 */ 100 pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02); 101 102 radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); 103 104 /* write radio config values to register */ 105 if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_5000_RF_CFG_TYPE_MAX) 106 iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, 107 EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | 108 EEPROM_RF_CFG_STEP_MSK(radio_cfg) | 109 EEPROM_RF_CFG_DASH_MSK(radio_cfg)); 110 111 /* set CSR_HW_CONFIG_REG for uCode use */ 112 iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, 113 CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | 114 CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); 115 116 spin_unlock_irqrestore(&priv->lock, flags); 117} 118 119 120 121/* 122 * EEPROM 123 */ 124static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) 125{ 126 u16 offset = 0; 127 128 if ((address & INDIRECT_ADDRESS) == 0) 129 return address; 130 131 switch (address & INDIRECT_TYPE_MSK) { 132 case INDIRECT_HOST: 133 offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_HOST); 134 break; 135 case INDIRECT_GENERAL: 136 offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_GENERAL); 137 break; 138 case INDIRECT_REGULATORY: 139 offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_REGULATORY); 140 break; 141 case INDIRECT_CALIBRATION: 142 offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_CALIBRATION); 143 break; 144 case INDIRECT_PROCESS_ADJST: 145 offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_PROCESS_ADJST); 146 break; 147 case INDIRECT_OTHERS: 148 offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_OTHERS); 149 break; 150 default: 151 IWL_ERROR("illegal indirect type: 0x%X\n", 152 address & INDIRECT_TYPE_MSK); 153 break; 154 } 155 156 /* translate the offset from words to byte */ 157 return (address & ADDRESS_MSK) + (offset << 1); 158} 159 160static int iwl5000_eeprom_check_version(struct iwl_priv *priv) 161{ 162 u16 eeprom_ver; 163 struct iwl_eeprom_calib_hdr { 164 u8 version; 165 u8 pa_type; 166 u16 voltage; 167 } *hdr; 168 169 eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); 170 171 hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, 172 EEPROM_5000_CALIB_ALL); 173 174 if (eeprom_ver < EEPROM_5000_EEPROM_VERSION || 175 hdr->version < EEPROM_5000_TX_POWER_VERSION) 176 goto err; 177 178 return 0; 179err: 180 IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", 181 eeprom_ver, EEPROM_5000_EEPROM_VERSION, 182 hdr->version, EEPROM_5000_TX_POWER_VERSION); 183 return -EINVAL; 184 185} 186 187#ifdef CONFIG_IWL5000_RUN_TIME_CALIB 188 189static void iwl5000_gain_computation(struct iwl_priv *priv, 190 u32 average_noise[NUM_RX_CHAINS], 191 u16 min_average_noise_antenna_i, 192 u32 min_average_noise) 193{ 194 int i; 195 s32 delta_g; 196 struct iwl_chain_noise_data *data = &priv->chain_noise_data; 197 198 /* Find Gain Code for the antennas B and C */ 199 for (i = 1; i < NUM_RX_CHAINS; i++) { 200 if ((data->disconn_array[i])) { 201 data->delta_gain_code[i] = 0; 202 continue; 203 } 204 delta_g = (1000 * ((s32)average_noise[0] - 205 (s32)average_noise[i])) / 1500; 206 /* bound gain by 2 bits value max, 3rd bit is sign */ 207 data->delta_gain_code[i] = 208 min(abs(delta_g), CHAIN_NOISE_MAX_DELTA_GAIN_CODE); 209 210 if (delta_g < 0) 211 /* set negative sign */ 212 data->delta_gain_code[i] |= (1 << 2); 213 } 214 215 IWL_DEBUG_CALIB("Delta gains: ANT_B = %d ANT_C = %d\n", 216 data->delta_gain_code[1], data->delta_gain_code[2]); 217 218 if (!data->radio_write) { 219 struct iwl5000_calibration_chain_noise_gain_cmd cmd; 220 memset(&cmd, 0, sizeof(cmd)); 221 222 cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD; 223 cmd.delta_gain_1 = data->delta_gain_code[1]; 224 cmd.delta_gain_2 = data->delta_gain_code[2]; 225 iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD, 226 sizeof(cmd), &cmd, NULL); 227 228 data->radio_write = 1; 229 data->state = IWL_CHAIN_NOISE_CALIBRATED; 230 } 231 232 data->chain_noise_a = 0; 233 data->chain_noise_b = 0; 234 data->chain_noise_c = 0; 235 data->chain_signal_a = 0; 236 data->chain_signal_b = 0; 237 data->chain_signal_c = 0; 238 data->beacon_count = 0; 239} 240 241 242static void iwl5000_chain_noise_reset(struct iwl_priv *priv) 243{ 244 struct iwl_chain_noise_data *data = &priv->chain_noise_data; 245 246 if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { 247 struct iwl5000_calibration_chain_noise_reset_cmd cmd; 248 249 memset(&cmd, 0, sizeof(cmd)); 250 cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; 251 if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, 252 sizeof(cmd), &cmd)) 253 IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n"); 254 data->state = IWL_CHAIN_NOISE_ACCUMULATE; 255 IWL_DEBUG_CALIB("Run chain_noise_calibrate\n"); 256 } 257} 258 259static struct iwl_sensitivity_ranges iwl5000_sensitivity = { 260 .min_nrg_cck = 95, 261 .max_nrg_cck = 0, 262 .auto_corr_min_ofdm = 90, 263 .auto_corr_min_ofdm_mrc = 170, 264 .auto_corr_min_ofdm_x1 = 120, 265 .auto_corr_min_ofdm_mrc_x1 = 240, 266 267 .auto_corr_max_ofdm = 120, 268 .auto_corr_max_ofdm_mrc = 210, 269 .auto_corr_max_ofdm_x1 = 155, 270 .auto_corr_max_ofdm_mrc_x1 = 290, 271 272 .auto_corr_min_cck = 125, 273 .auto_corr_max_cck = 200, 274 .auto_corr_min_cck_mrc = 170, 275 .auto_corr_max_cck_mrc = 400, 276 .nrg_th_cck = 95, 277 .nrg_th_ofdm = 95, 278}; 279 280#endif /* CONFIG_IWL5000_RUN_TIME_CALIB */ 281 282static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, 283 size_t offset) 284{ 285 u32 address = eeprom_indirect_address(priv, offset); 286 BUG_ON(address >= priv->cfg->eeprom_size); 287 return &priv->eeprom[address]; 288} 289 290static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) 291{ 292 if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || 293 (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { 294 IWL_ERROR("invalid queues_num, should be between %d and %d\n", 295 IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES); 296 return -EINVAL; 297 } 298 299 priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; 300 priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; 301 priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd); 302 priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; 303 priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; 304 if (priv->cfg->mod_params->amsdu_size_8K) 305 priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; 306 else 307 priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; 308 priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; 309 priv->hw_params.max_stations = IWL5000_STATION_COUNT; 310 priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; 311 priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; 312 priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE; 313 priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; 314 priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) | 315 BIT(IEEE80211_BAND_5GHZ); 316#ifdef CONFIG_IWL5000_RUN_TIME_CALIB 317 priv->hw_params.sens = &iwl5000_sensitivity; 318#endif 319 320 switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { 321 case CSR_HW_REV_TYPE_5100: 322 case CSR_HW_REV_TYPE_5150: 323 priv->hw_params.tx_chains_num = 1; 324 priv->hw_params.rx_chains_num = 2; 325 /* FIXME: move to ANT_A, ANT_B, ANT_C enum */ 326 priv->hw_params.valid_tx_ant = ANT_A; 327 priv->hw_params.valid_rx_ant = ANT_AB; 328 break; 329 case CSR_HW_REV_TYPE_5300: 330 case CSR_HW_REV_TYPE_5350: 331 priv->hw_params.tx_chains_num = 3; 332 priv->hw_params.rx_chains_num = 3; 333 priv->hw_params.valid_tx_ant = ANT_ABC; 334 priv->hw_params.valid_rx_ant = ANT_ABC; 335 break; 336 } 337 338 switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { 339 case CSR_HW_REV_TYPE_5100: 340 case CSR_HW_REV_TYPE_5300: 341 /* 5X00 wants in Celsius */ 342 priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; 343 break; 344 case CSR_HW_REV_TYPE_5150: 345 case CSR_HW_REV_TYPE_5350: 346 /* 5X50 wants in Kelvin */ 347 priv->hw_params.ct_kill_threshold = 348 CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); 349 break; 350 } 351 352 return 0; 353} 354 355static int iwl5000_alloc_shared_mem(struct iwl_priv *priv) 356{ 357 priv->shared_virt = pci_alloc_consistent(priv->pci_dev, 358 sizeof(struct iwl5000_shared), 359 &priv->shared_phys); 360 if (!priv->shared_virt) 361 return -ENOMEM; 362 363 memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared)); 364 365 priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed); 366 367 return 0; 368} 369 370static void iwl5000_free_shared_mem(struct iwl_priv *priv) 371{ 372 if (priv->shared_virt) 373 pci_free_consistent(priv->pci_dev, 374 sizeof(struct iwl5000_shared), 375 priv->shared_virt, 376 priv->shared_phys); 377} 378 379static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv) 380{ 381 struct iwl5000_shared *s = priv->shared_virt; 382 return le32_to_cpu(s->rb_closed) & 0xFFF; 383} 384 385/** 386 * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array 387 */ 388static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, 389 struct iwl_tx_queue *txq, 390 u16 byte_cnt) 391{ 392 struct iwl5000_shared *shared_data = priv->shared_virt; 393 int txq_id = txq->q.id; 394 u8 sec_ctl = 0; 395 u8 sta = 0; 396 int len; 397 398 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; 399 400 if (txq_id != IWL_CMD_QUEUE_NUM) { 401 sta = txq->cmd[txq->q.write_ptr].cmd.tx.sta_id; 402 sec_ctl = txq->cmd[txq->q.write_ptr].cmd.tx.sec_ctl; 403 404 switch (sec_ctl & TX_CMD_SEC_MSK) { 405 case TX_CMD_SEC_CCM: 406 len += CCMP_MIC_LEN; 407 break; 408 case TX_CMD_SEC_TKIP: 409 len += TKIP_ICV_LEN; 410 break; 411 case TX_CMD_SEC_WEP: 412 len += WEP_IV_LEN + WEP_ICV_LEN; 413 break; 414 } 415 } 416 417 IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. 418 tfd_offset[txq->q.write_ptr], byte_cnt, len); 419 420 IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. 421 tfd_offset[txq->q.write_ptr], sta_id, sta); 422 423 if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { 424 IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. 425 tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], 426 byte_cnt, len); 427 IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. 428 tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], 429 sta_id, sta); 430 } 431} 432 433static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) 434{ 435 u16 size = (u16)sizeof(struct iwl_addsta_cmd); 436 memcpy(data, cmd, size); 437 return size; 438} 439 440 441static int iwl5000_disable_tx_fifo(struct iwl_priv *priv) 442{ 443 unsigned long flags; 444 int ret; 445 446 spin_lock_irqsave(&priv->lock, flags); 447 448 ret = iwl_grab_nic_access(priv); 449 if (unlikely(ret)) { 450 IWL_ERROR("Tx fifo reset failed"); 451 spin_unlock_irqrestore(&priv->lock, flags); 452 return ret; 453 } 454 455 iwl_write_prph(priv, IWL50_SCD_TXFACT, 0); 456 iwl_release_nic_access(priv); 457 spin_unlock_irqrestore(&priv->lock, flags); 458 459 return 0; 460} 461 462/* Currently 5000 is the supperset of everything */ 463static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) 464{ 465 return len; 466} 467 468static struct iwl_hcmd_ops iwl5000_hcmd = { 469}; 470 471static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { 472 .get_hcmd_size = iwl5000_get_hcmd_size, 473 .build_addsta_hcmd = iwl5000_build_addsta_hcmd, 474#ifdef CONFIG_IWL5000_RUN_TIME_CALIB 475 .gain_computation = iwl5000_gain_computation, 476 .chain_noise_reset = iwl5000_chain_noise_reset, 477#endif 478}; 479 480static struct iwl_lib_ops iwl5000_lib = { 481 .set_hw_params = iwl5000_hw_set_hw_params, 482 .alloc_shared_mem = iwl5000_alloc_shared_mem, 483 .free_shared_mem = iwl5000_free_shared_mem, 484 .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, 485 .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, 486 .disable_tx_fifo = iwl5000_disable_tx_fifo, 487 .apm_ops = { 488 .init = iwl5000_apm_init, 489 .config = iwl5000_nic_config, 490 .set_pwr_src = iwl4965_set_pwr_src, 491 }, 492 .eeprom_ops = { 493 .regulatory_bands = { 494 EEPROM_5000_REG_BAND_1_CHANNELS, 495 EEPROM_5000_REG_BAND_2_CHANNELS, 496 EEPROM_5000_REG_BAND_3_CHANNELS, 497 EEPROM_5000_REG_BAND_4_CHANNELS, 498 EEPROM_5000_REG_BAND_5_CHANNELS, 499 EEPROM_5000_REG_BAND_24_FAT_CHANNELS, 500 EEPROM_5000_REG_BAND_52_FAT_CHANNELS 501 }, 502 .verify_signature = iwlcore_eeprom_verify_signature, 503 .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, 504 .release_semaphore = iwlcore_eeprom_release_semaphore, 505 .check_version = iwl5000_eeprom_check_version, 506 .query_addr = iwl5000_eeprom_query_addr, 507 }, 508}; 509 510static struct iwl_ops iwl5000_ops = { 511 .lib = &iwl5000_lib, 512 .hcmd = &iwl5000_hcmd, 513 .utils = &iwl5000_hcmd_utils, 514}; 515 516static struct iwl_mod_params iwl50_mod_params = { 517 .num_of_queues = IWL50_NUM_QUEUES, 518 .enable_qos = 1, 519 .amsdu_size_8K = 1, 520 .restart_fw = 1, 521 /* the rest are 0 by default */ 522}; 523 524 525struct iwl_cfg iwl5300_agn_cfg = { 526 .name = "5300AGN", 527 .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", 528 .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, 529 .ops = &iwl5000_ops, 530 .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, 531 .mod_params = &iwl50_mod_params, 532}; 533 534struct iwl_cfg iwl5100_agn_cfg = { 535 .name = "5100AGN", 536 .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", 537 .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, 538 .ops = &iwl5000_ops, 539 .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, 540 .mod_params = &iwl50_mod_params, 541}; 542 543struct iwl_cfg iwl5350_agn_cfg = { 544 .name = "5350AGN", 545 .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", 546 .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, 547 .ops = &iwl5000_ops, 548 .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, 549 .mod_params = &iwl50_mod_params, 550}; 551 552module_param_named(disable50, iwl50_mod_params.disable, int, 0444); 553MODULE_PARM_DESC(disable50, 554 "manually disable the 50XX radio (default 0 [radio on])"); 555module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); 556MODULE_PARM_DESC(swcrypto50, 557 "using software crypto engine (default 0 [hardware])\n"); 558module_param_named(debug50, iwl50_mod_params.debug, int, 0444); 559MODULE_PARM_DESC(debug50, "50XX debug output mask"); 560module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); 561MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); 562module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444); 563MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality"); 564module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444); 565MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series"); 566module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444); 567MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error"); 568