iwl-5000.c revision 83d527d9e8f9aff92cbd33f208f77c055dabb499
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.max_rxq_size = RX_QUEUE_SIZE; 302 priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; 303 if (priv->cfg->mod_params->amsdu_size_8K) 304 priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; 305 else 306 priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; 307 priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; 308 priv->hw_params.max_stations = IWL5000_STATION_COUNT; 309 priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; 310 priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; 311 priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE; 312 priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; 313 priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) | 314 BIT(IEEE80211_BAND_5GHZ); 315#ifdef CONFIG_IWL5000_RUN_TIME_CALIB 316 priv->hw_params.sens = &iwl5000_sensitivity; 317#endif 318 319 switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { 320 case CSR_HW_REV_TYPE_5100: 321 case CSR_HW_REV_TYPE_5150: 322 priv->hw_params.tx_chains_num = 1; 323 priv->hw_params.rx_chains_num = 2; 324 /* FIXME: move to ANT_A, ANT_B, ANT_C enum */ 325 priv->hw_params.valid_tx_ant = ANT_A; 326 priv->hw_params.valid_rx_ant = ANT_AB; 327 break; 328 case CSR_HW_REV_TYPE_5300: 329 case CSR_HW_REV_TYPE_5350: 330 priv->hw_params.tx_chains_num = 3; 331 priv->hw_params.rx_chains_num = 3; 332 priv->hw_params.valid_tx_ant = ANT_ABC; 333 priv->hw_params.valid_rx_ant = ANT_ABC; 334 break; 335 } 336 337 switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { 338 case CSR_HW_REV_TYPE_5100: 339 case CSR_HW_REV_TYPE_5300: 340 /* 5X00 wants in Celsius */ 341 priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; 342 break; 343 case CSR_HW_REV_TYPE_5150: 344 case CSR_HW_REV_TYPE_5350: 345 /* 5X50 wants in Kelvin */ 346 priv->hw_params.ct_kill_threshold = 347 CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); 348 break; 349 } 350 351 return 0; 352} 353 354static int iwl5000_alloc_shared_mem(struct iwl_priv *priv) 355{ 356 priv->shared_virt = pci_alloc_consistent(priv->pci_dev, 357 sizeof(struct iwl5000_shared), 358 &priv->shared_phys); 359 if (!priv->shared_virt) 360 return -ENOMEM; 361 362 memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared)); 363 364 priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed); 365 366 return 0; 367} 368 369static void iwl5000_free_shared_mem(struct iwl_priv *priv) 370{ 371 if (priv->shared_virt) 372 pci_free_consistent(priv->pci_dev, 373 sizeof(struct iwl5000_shared), 374 priv->shared_virt, 375 priv->shared_phys); 376} 377 378static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv) 379{ 380 struct iwl5000_shared *s = priv->shared_virt; 381 return le32_to_cpu(s->rb_closed) & 0xFFF; 382} 383 384/** 385 * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array 386 */ 387static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, 388 struct iwl_tx_queue *txq, 389 u16 byte_cnt) 390{ 391 struct iwl5000_shared *shared_data = priv->shared_virt; 392 int txq_id = txq->q.id; 393 u8 sec_ctl = 0; 394 u8 sta = 0; 395 int len; 396 397 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; 398 399 if (txq_id != IWL_CMD_QUEUE_NUM) { 400 sta = txq->cmd[txq->q.write_ptr].cmd.tx.sta_id; 401 sec_ctl = txq->cmd[txq->q.write_ptr].cmd.tx.sec_ctl; 402 403 switch (sec_ctl & TX_CMD_SEC_MSK) { 404 case TX_CMD_SEC_CCM: 405 len += CCMP_MIC_LEN; 406 break; 407 case TX_CMD_SEC_TKIP: 408 len += TKIP_ICV_LEN; 409 break; 410 case TX_CMD_SEC_WEP: 411 len += WEP_IV_LEN + WEP_ICV_LEN; 412 break; 413 } 414 } 415 416 IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. 417 tfd_offset[txq->q.write_ptr], byte_cnt, len); 418 419 IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. 420 tfd_offset[txq->q.write_ptr], sta_id, sta); 421 422 if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { 423 IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. 424 tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], 425 byte_cnt, len); 426 IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. 427 tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], 428 sta_id, sta); 429 } 430} 431 432static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) 433{ 434 u16 size = (u16)sizeof(struct iwl_addsta_cmd); 435 memcpy(data, cmd, size); 436 return size; 437} 438 439 440static int iwl5000_disable_tx_fifo(struct iwl_priv *priv) 441{ 442 unsigned long flags; 443 int ret; 444 445 spin_lock_irqsave(&priv->lock, flags); 446 447 ret = iwl_grab_nic_access(priv); 448 if (unlikely(ret)) { 449 IWL_ERROR("Tx fifo reset failed"); 450 spin_unlock_irqrestore(&priv->lock, flags); 451 return ret; 452 } 453 454 iwl_write_prph(priv, IWL50_SCD_TXFACT, 0); 455 iwl_release_nic_access(priv); 456 spin_unlock_irqrestore(&priv->lock, flags); 457 458 return 0; 459} 460 461/* Currently 5000 is the supperset of everything */ 462static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) 463{ 464 return len; 465} 466 467static struct iwl_hcmd_ops iwl5000_hcmd = { 468}; 469 470static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { 471 .get_hcmd_size = iwl5000_get_hcmd_size, 472 .build_addsta_hcmd = iwl5000_build_addsta_hcmd, 473#ifdef CONFIG_IWL5000_RUN_TIME_CALIB 474 .gain_computation = iwl5000_gain_computation, 475 .chain_noise_reset = iwl5000_chain_noise_reset, 476#endif 477}; 478 479static struct iwl_lib_ops iwl5000_lib = { 480 .set_hw_params = iwl5000_hw_set_hw_params, 481 .alloc_shared_mem = iwl5000_alloc_shared_mem, 482 .free_shared_mem = iwl5000_free_shared_mem, 483 .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, 484 .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, 485 .disable_tx_fifo = iwl5000_disable_tx_fifo, 486 .apm_ops = { 487 .init = iwl5000_apm_init, 488 .config = iwl5000_nic_config, 489 .set_pwr_src = iwl4965_set_pwr_src, 490 }, 491 .eeprom_ops = { 492 .regulatory_bands = { 493 EEPROM_5000_REG_BAND_1_CHANNELS, 494 EEPROM_5000_REG_BAND_2_CHANNELS, 495 EEPROM_5000_REG_BAND_3_CHANNELS, 496 EEPROM_5000_REG_BAND_4_CHANNELS, 497 EEPROM_5000_REG_BAND_5_CHANNELS, 498 EEPROM_5000_REG_BAND_24_FAT_CHANNELS, 499 EEPROM_5000_REG_BAND_52_FAT_CHANNELS 500 }, 501 .verify_signature = iwlcore_eeprom_verify_signature, 502 .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, 503 .release_semaphore = iwlcore_eeprom_release_semaphore, 504 .check_version = iwl5000_eeprom_check_version, 505 .query_addr = iwl5000_eeprom_query_addr, 506 }, 507}; 508 509static struct iwl_ops iwl5000_ops = { 510 .lib = &iwl5000_lib, 511 .hcmd = &iwl5000_hcmd, 512 .utils = &iwl5000_hcmd_utils, 513}; 514 515static struct iwl_mod_params iwl50_mod_params = { 516 .num_of_queues = IWL50_NUM_QUEUES, 517 .enable_qos = 1, 518 .amsdu_size_8K = 1, 519 .restart_fw = 1, 520 /* the rest are 0 by default */ 521}; 522 523 524struct iwl_cfg iwl5300_agn_cfg = { 525 .name = "5300AGN", 526 .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", 527 .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, 528 .ops = &iwl5000_ops, 529 .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, 530 .mod_params = &iwl50_mod_params, 531}; 532 533struct iwl_cfg iwl5100_agn_cfg = { 534 .name = "5100AGN", 535 .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", 536 .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, 537 .ops = &iwl5000_ops, 538 .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, 539 .mod_params = &iwl50_mod_params, 540}; 541 542struct iwl_cfg iwl5350_agn_cfg = { 543 .name = "5350AGN", 544 .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", 545 .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, 546 .ops = &iwl5000_ops, 547 .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, 548 .mod_params = &iwl50_mod_params, 549}; 550 551module_param_named(disable50, iwl50_mod_params.disable, int, 0444); 552MODULE_PARM_DESC(disable50, 553 "manually disable the 50XX radio (default 0 [radio on])"); 554module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); 555MODULE_PARM_DESC(swcrypto50, 556 "using software crypto engine (default 0 [hardware])\n"); 557module_param_named(debug50, iwl50_mod_params.debug, int, 0444); 558MODULE_PARM_DESC(debug50, "50XX debug output mask"); 559module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); 560MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); 561module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444); 562MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality"); 563module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444); 564MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series"); 565module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444); 566MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error"); 567