diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
28 files changed, 2878 insertions, 1229 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index cf3fbc6b98e..a95caa01414 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -117,8 +117,8 @@ static struct iwl_lib_ops iwl1000_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, @@ -149,12 +149,15 @@ struct iwl_cfg iwl1000_bgn_cfg = { .ucode_api_min = IWL1000_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, .ops = &iwl1000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .max_ll_items = OTP_MAX_LL_ITEMS_1000, + .shadow_ram_support = false, + .ht_greenfield_support = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index b569c6f38e5..16772780c5b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -176,7 +176,7 @@ struct iwl3945_eeprom { * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory * txpower (MSB). * - * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) + * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) * channels (only for 4965, not supported by 3945) appear later in the EEPROM. * * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e1b0ef3c56a..e9a685d8e3a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -349,12 +349,13 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv, * *****************************************************************************/ -void iwl3945_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +void iwl3945_hw_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (void *)rxb->skb->data; IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(struct iwl3945_notif_statistics), - le32_to_cpu(pkt->len)); + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39)); @@ -502,14 +503,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(IWL_DL_RX, data, length); + iwl_print_hex_dump(priv, IWL_DL_RX, data, length); } static void iwl3945_dbg_report_frame(struct iwl_priv *priv, struct iwl_rx_packet *pkt, struct ieee80211_hdr *header, int group100) { - if (iwl_debug_level & IWL_DL_RX) + if (iwl_get_debug_level(priv) & IWL_DL_RX) _iwl3945_dbg_report_frame(priv, pkt, header, group100); } @@ -544,9 +545,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, struct ieee80211_rx_status *stats) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; -#ifdef CONFIG_IWLWIFI_LEDS struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); -#endif struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); short len = le16_to_cpu(rx_hdr->len); @@ -577,6 +576,8 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, if (ieee80211_is_data(hdr->frame_control)) priv->rxtxpackets += len; #endif + iwl_update_stats(priv, false, hdr->frame_control, len); + memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); ieee80211_rx_irqsafe(priv->hw, rxb->skb); rxb->skb = NULL; @@ -679,6 +680,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, /* Set "1" to report good data frames in groups of 100 */ iwl3945_dbg_report_frame(priv, pkt, header, 1); + iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header); if (network_packet) { priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); @@ -2851,8 +2853,8 @@ static struct iwl_lib_ops iwl3945_lib = { EEPROM_REGULATORY_BAND_3_CHANNELS, EEPROM_REGULATORY_BAND_4_CHANNELS, EEPROM_REGULATORY_BAND_5_CHANNELS, - EEPROM_REGULATORY_BAND_NO_FAT, - EEPROM_REGULATORY_BAND_NO_FAT, + EEPROM_REGULATORY_BAND_NO_HT40, + EEPROM_REGULATORY_BAND_NO_HT40, }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwl3945_eeprom_acquire_semaphore, @@ -2888,7 +2890,8 @@ static struct iwl_cfg iwl3945_bg_cfg = { .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2901,7 +2904,8 @@ static struct iwl_cfg iwl3945_abg_cfg = { .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, .mod_params = &iwl3945_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; struct pci_device_id iwl3945_hw_card_ids[] = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index a71a489096f..b34322a3245 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -188,7 +188,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * * 1) Regulatory information (max txpower and channel usage flags) is provided * separately for each channel that can possibly supported by 4965. - * 40 MHz wide (.11n fat) channels are listed separately from 20 MHz + * 40 MHz wide (.11n HT40) channels are listed separately from 20 MHz * (legacy) channels. * * See struct iwl4965_eeprom_channel for format, and struct iwl4965_eeprom @@ -251,8 +251,8 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * no reduction (such as with regulatory txpower limits) is required. * * Saturation and Backoff values apply equally to 20 Mhz (legacy) channel - * widths and 40 Mhz (.11n fat) channel widths; there is no separate - * factory measurement for fat channels. + * widths and 40 Mhz (.11n HT40) channel widths; there is no separate + * factory measurement for ht40 channels. * * The result of this step is the final target txpower. The rest of * the steps figure out the proper settings for the device to achieve diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 670214823cb..6a13bfbc9d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -46,7 +46,7 @@ #include "iwl-sta.h" static int iwl4965_send_tx_power(struct iwl_priv *priv); -static int iwl4965_hw_get_temperature(const struct iwl_priv *priv); +static int iwl4965_hw_get_temperature(struct iwl_priv *priv); /* Highest firmware API version supported */ #define IWL4965_UCODE_API_MAX 2 @@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Begin load bsm\n"); - priv->ucode_type = UCODE_INIT; + priv->ucode_type = UCODE_RT; /* make sure bootstrap program is no larger than BSM's SRAM size */ if (len > IWL49_MAX_BSM_SIZE) @@ -256,8 +256,6 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) */ static void iwl4965_init_alive_start(struct iwl_priv *priv) { - int ret; - /* Check alive response for "valid" sign from uCode */ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { /* We had an error bringing up the hardware, so take it @@ -289,35 +287,13 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n"); goto restart; } - priv->ucode_type = UCODE_RT; - if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { - IWL_WARN(priv, "Runtime uCode already alive? " - "Waiting for alive anyway\n"); - clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status); - } - ret = wait_event_interruptible_timeout( - priv->wait_command_queue, - test_bit(STATUS_RT_UCODE_ALIVE, &priv->status), - UCODE_ALIVE_TIMEOUT); - if (!ret) { - /* FIXME: if STATUS_RT_UCODE_ALIVE timeout - * go back to restart the download Init uCode again - * this might cause to trap in the restart loop - */ - priv->ucode_type = UCODE_NONE; - if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) { - IWL_ERR(priv, "Runtime timeout after %dms\n", - jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); - goto restart; - } - } return; restart: queue_work(priv->workqueue, &priv->restart); } -static bool is_fat_channel(__le32 rxon_flags) +static bool is_ht40_channel(__le32 rxon_flags) { int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK) >> RXON_FLG_CHANNEL_MODE_POS; @@ -806,7 +782,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE; priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; - priv->hw_params.fat_channel = BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -1266,7 +1242,7 @@ static const struct gain_entry gain_table[2][108] = { }; static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, - u8 is_fat, u8 ctrl_chan_high, + u8 is_ht40, u8 ctrl_chan_high, struct iwl4965_tx_power_db *tx_power_tbl) { u8 saturation_power; @@ -1298,8 +1274,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, user_target_power = 2 * priv->tx_power_user_lmt; /* Get current (RXON) channel, band, width */ - IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_fat %d\n", channel, band, - is_fat); + IWL_DEBUG_TXPOWER(priv, "chan %d band %d is_ht40 %d\n", channel, band, + is_ht40); ch_info = iwl_get_channel_info(priv, priv->band, channel); @@ -1318,7 +1294,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, IWL_DEBUG_TXPOWER(priv, "channel %d belongs to txatten group %d\n", channel, txatten_grp); - if (is_fat) { + if (is_ht40) { if (ctrl_chan_high) channel -= 2; else @@ -1342,8 +1318,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, /* regulatory txpower limits ... reg_limit values are in half-dBm, * max_power_avg values are in dBm, convert * 2 */ - if (is_fat) - reg_limit = ch_info->fat_max_power_avg * 2; + if (is_ht40) + reg_limit = ch_info->ht40_max_power_avg * 2; else reg_limit = ch_info->max_power_avg * 2; @@ -1509,7 +1485,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, /** * iwl4965_send_tx_power - Configure the TXPOWER level user limit * - * Uses the active RXON for channel, band, and characteristics (fat, high) + * Uses the active RXON for channel, band, and characteristics (ht40, high) * The power limit is taken from priv->tx_power_user_lmt. */ static int iwl4965_send_tx_power(struct iwl_priv *priv) @@ -1517,7 +1493,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) struct iwl4965_txpowertable_cmd cmd = { 0 }; int ret; u8 band = 0; - bool is_fat = false; + bool is_ht40 = false; u8 ctrl_chan_high = 0; if (test_bit(STATUS_SCANNING, &priv->status)) { @@ -1530,9 +1506,9 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) band = priv->band == IEEE80211_BAND_2GHZ; - is_fat = is_fat_channel(priv->active_rxon.flags); + is_ht40 = is_ht40_channel(priv->active_rxon.flags); - if (is_fat && + if (is_ht40 && (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) ctrl_chan_high = 1; @@ -1541,7 +1517,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) ret = iwl4965_fill_txpower_tbl(priv, band, le16_to_cpu(priv->active_rxon.channel), - is_fat, ctrl_chan_high, &cmd.tx_power); + is_ht40, ctrl_chan_high, &cmd.tx_power); if (ret) goto out; @@ -1595,7 +1571,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) { int rc; u8 band = 0; - bool is_fat = false; + bool is_ht40 = false; u8 ctrl_chan_high = 0; struct iwl4965_channel_switch_cmd cmd = { 0 }; const struct iwl_channel_info *ch_info; @@ -1604,9 +1580,9 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) ch_info = iwl_get_channel_info(priv, priv->band, channel); - is_fat = is_fat_channel(priv->staging_rxon.flags); + is_ht40 = is_ht40_channel(priv->staging_rxon.flags); - if (is_fat && + if (is_ht40 && (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) ctrl_chan_high = 1; @@ -1621,7 +1597,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) else cmd.expect_beacon = 1; - rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat, + rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40, ctrl_chan_high, &cmd.tx_power); if (rc) { IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc); @@ -1680,7 +1656,7 @@ static s32 sign_extend(u32 oper, int index) * * A return of <0 indicates bogus data in the statistics */ -static int iwl4965_hw_get_temperature(const struct iwl_priv *priv) +static int iwl4965_hw_get_temperature(struct iwl_priv *priv) { s32 temperature; s32 vt; @@ -1688,8 +1664,8 @@ static int iwl4965_hw_get_temperature(const struct iwl_priv *priv) u32 R4; if (test_bit(STATUS_TEMPERATURE, &priv->status) && - (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) { - IWL_DEBUG_TEMP(priv, "Running FAT temperature calibration\n"); + (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)) { + IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n"); R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]); @@ -2330,8 +2306,8 @@ static struct iwl_lib_ops iwl4965_lib = { EEPROM_REGULATORY_BAND_3_CHANNELS, EEPROM_REGULATORY_BAND_4_CHANNELS, EEPROM_REGULATORY_BAND_5_CHANNELS, - EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS, - EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS + EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS, + EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, @@ -2368,7 +2344,8 @@ struct iwl_cfg iwl4965_agn_cfg = { .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, - .use_isr_legacy = true + .use_isr_legacy = true, + .ht_greenfield_support = false, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 87957c05283..1d539e3b8db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -494,7 +494,7 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, { struct iwl_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; - int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; + int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; int index; /* reduce the size of the length field itself */ @@ -845,7 +845,7 @@ int iwl5000_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_bsm_size = 0; - priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) | + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -1411,6 +1411,7 @@ static void iwl5150_temperature(struct iwl_priv *priv) vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; /* now vt hold the temperature in Kelvin */ priv->temperature = KELVIN_TO_CELSIUS(vt); + iwl_tt_handler(priv); } /* Calc max signal level (dBm) among 3 possible receivers */ @@ -1547,8 +1548,8 @@ struct iwl_lib_ops iwl5000_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, @@ -1597,8 +1598,8 @@ static struct iwl_lib_ops iwl5150_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, @@ -1652,6 +1653,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_bg_cfg = { @@ -1668,6 +1670,7 @@ struct iwl_cfg iwl5100_bg_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -1684,6 +1687,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -1700,6 +1704,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1716,6 +1721,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1732,6 +1738,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .need_pll_cfg = true, + .ht_greenfield_support = true, }; MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 4450943d3da..82b9c93dff5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -46,8 +46,8 @@ #include "iwl-5000-hw.h" /* Highest firmware API version supported */ -#define IWL6000_UCODE_API_MAX 3 -#define IWL6050_UCODE_API_MAX 3 +#define IWL6000_UCODE_API_MAX 4 +#define IWL6050_UCODE_API_MAX 4 /* Lowest firmware API version supported */ #define IWL6000_UCODE_API_MIN 1 @@ -118,14 +118,15 @@ static struct iwl_lib_ops iwl6000_lib = { EEPROM_5000_REG_BAND_3_CHANNELS, EEPROM_5000_REG_BAND_4_CHANNELS, EEPROM_5000_REG_BAND_5_CHANNELS, - EEPROM_5000_REG_BAND_24_FAT_CHANNELS, - EEPROM_5000_REG_BAND_52_FAT_CHANNELS + EEPROM_5000_REG_BAND_24_HT40_CHANNELS, + EEPROM_5000_REG_BAND_52_HT40_CHANNELS }, .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, .calib_version = iwl5000_eeprom_calib_version, .query_addr = iwl5000_eeprom_query_addr, + .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, .post_associate = iwl_post_associate, .isr = iwl_isr_ict, @@ -161,7 +162,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -169,6 +170,9 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = false, .pa_type = IWL_PA_HYBRID, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, }; /* @@ -181,7 +185,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -189,6 +193,9 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .valid_rx_ant = ANT_BC, .need_pll_cfg = false, .pa_type = IWL_PA_INTERNAL, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -198,7 +205,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -206,6 +213,9 @@ struct iwl_cfg iwl6050_2agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -215,7 +225,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .ucode_api_min = IWL6000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -223,6 +233,9 @@ struct iwl_cfg iwl6000_3agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -232,7 +245,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, - .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, @@ -240,6 +253,9 @@ struct iwl_cfg iwl6050_3agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 52a4810274e..40b207aa8fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -97,7 +97,7 @@ struct iwl_scale_tbl_info { enum iwl_table_type lq_type; u8 ant_type; u8 is_SGI; /* 1 = short guard interval */ - u8 is_fat; /* 1 = 40 MHz channel width */ + u8 is_ht40; /* 1 = 40 MHz channel width */ u8 is_dup; /* 1 = duplicated data streams */ u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ u8 max_search; /* maximun number of tables we can search */ @@ -332,6 +332,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, } else return MAX_TID_COUNT; + if (unlikely(tid >= TID_MAX_LOAD_COUNT)) + return MAX_TID_COUNT; + tl = &lq_data->load[tid]; curr_time -= curr_time % TID_ROUND_VALUE; @@ -539,11 +542,11 @@ static u32 rate_n_flags_from_tbl(struct iwl_priv *priv, RATE_MCS_ANT_ABC_MSK); if (is_Ht(tbl->lq_type)) { - if (tbl->is_fat) { + if (tbl->is_ht40) { if (tbl->is_dup) rate_n_flags |= RATE_MCS_DUP_MSK; else - rate_n_flags |= RATE_MCS_FAT_MSK; + rate_n_flags |= RATE_MCS_HT40_MSK; } if (tbl->is_SGI) rate_n_flags |= RATE_MCS_SGI_MSK; @@ -579,7 +582,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, return -EINVAL; } tbl->is_SGI = 0; /* default legacy setup */ - tbl->is_fat = 0; + tbl->is_ht40 = 0; tbl->is_dup = 0; tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); tbl->lq_type = LQ_NONE; @@ -598,9 +601,9 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, if (rate_n_flags & RATE_MCS_SGI_MSK) tbl->is_SGI = 1; - if ((rate_n_flags & RATE_MCS_FAT_MSK) || + if ((rate_n_flags & RATE_MCS_HT40_MSK) || (rate_n_flags & RATE_MCS_DUP_MSK)) - tbl->is_fat = 1; + tbl->is_ht40 = 1; if (rate_n_flags & RATE_MCS_DUP_MSK) tbl->is_dup = 1; @@ -654,19 +657,15 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, return 1; } -/* in 4965 we don't use greenfield at all */ -static inline u8 rs_use_green(struct iwl_priv *priv, - struct ieee80211_conf *conf) +/** + * Green-field mode is valid if the station supports it and + * there are no non-GF stations present in the BSS. + */ +static inline u8 rs_use_green(struct ieee80211_sta *sta, + struct iwl_ht_info *ht_conf) { - u8 is_green; - - if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) - is_green = 0; - else - is_green = (conf_is_ht(conf) && - priv->current_ht_config.is_green_field && - !priv->current_ht_config.non_GF_STA_present); - return is_green; + return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && + !(ht_conf->non_GF_STA_present); } /** @@ -776,7 +775,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, if (num_of_ant(tbl->ant_type) > 1) tbl->ant_type = ANT_A;/*FIXME:RS*/ - tbl->is_fat = 0; + tbl->is_ht40 = 0; tbl->is_SGI = 0; tbl->max_search = IWL_MAX_SEARCH; } @@ -819,15 +818,15 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, { int status; u8 retries; - int rs_index, index = 0; + int rs_index, mac_index, index = 0; struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_link_quality_cmd *table; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl_priv *priv = (struct iwl_priv *)priv_r; - struct ieee80211_hw *hw = priv->hw; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_rate_scale_data *window = NULL; struct iwl_rate_scale_data *search_win = NULL; + enum mac80211_rate_control_flags mac_flags; u32 tx_rate; struct iwl_scale_tbl_info tbl_type; struct iwl_scale_tbl_info *curr_tbl, *search_tbl; @@ -877,17 +876,24 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; + mac_flags = info->status.rates[0].flags; + mac_index = info->status.rates[0].idx; + /* For HT packets, map MCS to PLCP */ + if (mac_flags & IEEE80211_TX_RC_MCS) { + mac_index &= RATE_MCS_CODE_MSK; /* Remove # of streams */ + if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE)) + mac_index++; + } - if ((info->status.rates[0].idx < 0) || - (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) || - (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || - (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) || + if ((mac_index < 0) || + (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || + (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || + (tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA)) || (tbl_type.ant_type != info->antenna_sel_tx) || - (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) || - (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) || - (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) { - IWL_DEBUG_RATE(priv, "initial rate does not match 0x%x\n", tx_rate); + (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) || + (!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || + (rs_index != mac_index)) { + IWL_DEBUG_RATE(priv, "initial rate %d does not match %d (0x%x)\n", mac_index, rs_index, tx_rate); /* the last LQ command could failed so the LQ in ucode not * the same in driver sync up */ @@ -1049,7 +1055,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, else tbl->expected_tpt = expected_tpt_A; } else if (is_siso(tbl->lq_type)) { - if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_ht40 && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_siso40MHzSGI; else @@ -1059,7 +1065,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, else tbl->expected_tpt = expected_tpt_siso20MHz; } else if (is_mimo2(tbl->lq_type)) { - if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_ht40 && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI; else @@ -1069,7 +1075,7 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, else tbl->expected_tpt = expected_tpt_mimo2_20MHz; } else if (is_mimo3(tbl->lq_type)) { - if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_ht40 && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI; else @@ -1217,22 +1223,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_mimo2_rate; - if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) - tbl->is_fat = 1; + if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) + tbl->is_ht40 = 1; else - tbl->is_fat = 0; - - /* FIXME: - don't toggle SGI here - if (tbl->is_fat) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ + tbl->is_ht40 = 0; rs_set_expected_tpt_table(lq_sta, tbl); @@ -1283,22 +1277,10 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; rate_mask = lq_sta->active_mimo3_rate; - if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) - tbl->is_fat = 1; + if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) + tbl->is_ht40 = 1; else - tbl->is_fat = 0; - - /* FIXME: - don't toggle SGI here - if (tbl->is_fat) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ + tbl->is_ht40 = 0; rs_set_expected_tpt_table(lq_sta, tbl); @@ -1342,22 +1324,10 @@ static int rs_switch_to_siso(struct iwl_priv *priv, tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_siso_rate; - if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) - tbl->is_fat = 1; + if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap)) + tbl->is_ht40 = 1; else - tbl->is_fat = 0; - - /* FIXME: - don't toggle SGI here - if (tbl->is_fat) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ + tbl->is_ht40 = 0; if (is_green) tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ @@ -1401,7 +1371,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, if (!iwl_ht_enabled(priv)) /* stay in Legacy */ tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; - else if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && + else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE && tbl->action > IWL_LEGACY_SWITCH_SISO) tbl->action = IWL_LEGACY_SWITCH_SISO; for (; ;) { @@ -1527,6 +1497,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); struct iwl_rate_scale_data *window = &(tbl->win[index]); + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; @@ -1535,7 +1506,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, u8 update_search_tbl_counter = 0; int ret; - if (iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE && + if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE && tbl->action > IWL_SISO_SWITCH_ANTENNA2) { /* stay in SISO */ tbl->action = IWL_SISO_SWITCH_ANTENNA1; @@ -1586,13 +1557,11 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, goto out; break; case IWL_SISO_SWITCH_GI: - if (!tbl->is_fat && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_fat && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: SISO toggle SGI/NGI\n"); @@ -1666,6 +1635,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); struct iwl_rate_scale_data *window = &(tbl->win[index]); + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; @@ -1674,7 +1644,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, u8 update_search_tbl_counter = 0; int ret; - if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && + if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) && (tbl->action < IWL_MIMO2_SWITCH_SISO_A || tbl->action > IWL_MIMO2_SWITCH_SISO_C)) { /* switch in SISO */ @@ -1726,13 +1696,11 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, break; case IWL_MIMO2_SWITCH_GI: - if (!tbl->is_fat && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_fat && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n"); @@ -1808,6 +1776,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, struct iwl_scale_tbl_info *search_tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); struct iwl_rate_scale_data *window = &(tbl->win[index]); + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action = tbl->action; @@ -1816,7 +1785,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, int ret; u8 update_search_tbl_counter = 0; - if ((iwl_tx_ant_restriction(priv) == IWL_TX_SINGLE) && + if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) && (tbl->action < IWL_MIMO3_SWITCH_SISO_A || tbl->action > IWL_MIMO3_SWITCH_SISO_C)) { /* switch in SISO */ @@ -1890,13 +1859,11 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, break; case IWL_MIMO3_SWITCH_GI: - if (!tbl->is_fat && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) + if (!tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_20)) break; - if (tbl->is_fat && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) + if (tbl->is_ht40 && !(ht_cap->cap & + IEEE80211_HT_CAP_SGI_40)) break; IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n"); @@ -2108,7 +2075,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (is_legacy(tbl->lq_type)) lq_sta->is_green = 0; else - lq_sta->is_green = rs_use_green(priv, conf); + lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config); is_green = lq_sta->is_green; /* current tx rate */ @@ -2202,7 +2169,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, /* If we are searching for better modulation mode, check success. */ if (lq_sta->search_better_tbl && - (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI)) { + (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI)) { /* If good success, continue using the "search" mode; * no need to send new link quality command, since we're * continuing to use the setup that we've been trying. */ @@ -2332,7 +2299,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, scale_action = 0; if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type)) scale_action = -1; - if (iwl_tx_ant_restriction(priv) != IWL_TX_MULTI && + if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI && (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) scale_action = -1; switch (scale_action) { @@ -2368,7 +2335,7 @@ lq_update: rate = rs_update_rate_tbl(priv, lq_sta, tbl, index, is_green); - if (iwl_tx_ant_restriction(priv) == IWL_TX_MULTI) { + if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) { /* Should we stay with this modulation mode, * or search for a new one? */ rs_stay_in_table(lq_sta); @@ -2466,7 +2433,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, int rate_idx; int i; u32 rate; - u8 use_green = rs_use_green(priv, conf); + u8 use_green = rs_use_green(sta, &priv->current_ht_config); u8 active_tbl = 0; u8 valid_tx_ant; @@ -2519,6 +2486,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_supported_band *sband = txrc->sband; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = priv_sta; @@ -2551,7 +2519,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", hdr->addr1); sta_id = iwl_add_station(priv, hdr->addr1, - false, CMD_ASYNC, NULL); + false, CMD_ASYNC, ht_cap); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2576,15 +2544,20 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI; if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK) info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA; - if (lq_sta->last_rate_n_flags & RATE_MCS_FAT_MSK) + if (lq_sta->last_rate_n_flags & RATE_MCS_HT40_MSK) info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK) info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; } else { - if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) + /* Check for invalid rates */ + if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) || + ((sband->band == IEEE80211_BAND_5GHZ) && + (rate_idx < IWL_FIRST_OFDM_RATE))) rate_idx = rate_lowest_index(sband, sta); + /* On valid 5 GHz rate, adjust index */ else if (sband->band == IEEE80211_BAND_5GHZ) rate_idx -= IWL_FIRST_OFDM_RATE; + info->control.rates[0].flags = 0; } info->control.rates[0].idx = rate_idx; @@ -2620,10 +2593,8 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, int i, j; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct iwl_lq_sta *lq_sta = priv_sta; - u16 mask_bit = 0; - int count; - int start_rate = 0; lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->supp_rates[sband->band]; @@ -2648,7 +2619,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); sta_id = iwl_add_station(priv, sta->addr, false, - CMD_ASYNC, NULL); + CMD_ASYNC, ht_cap); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2661,7 +2632,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->is_dup = 0; lq_sta->max_rate_idx = -1; lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; - lq_sta->is_green = rs_use_green(priv, conf); + lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config); lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); lq_sta->active_rate_basic = priv->active_rate_basic; lq_sta->band = priv->band; @@ -2669,19 +2640,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), * supp_rates[] does not; shift to convert format, force 9 MBits off. */ - lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1; - lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1; + lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; + lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; lq_sta->active_siso_rate &= ~((u16)0x2); lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; /* Same here */ - lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1; - lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1; + lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; + lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; lq_sta->active_mimo2_rate &= ~((u16)0x2); lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1; - lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1; + lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1; + lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1; lq_sta->active_mimo3_rate &= ~((u16)0x2); lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; @@ -2698,20 +2669,10 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->drv = priv; - /* Find highest tx rate supported by hardware and destination station */ - mask_bit = sta->supp_rates[sband->band]; - count = sband->n_bitrates; - if (sband->band == IEEE80211_BAND_5GHZ) { - count += IWL_FIRST_OFDM_RATE; - start_rate = IWL_FIRST_OFDM_RATE; - mask_bit <<= IWL_FIRST_OFDM_RATE; - } - - mask_bit = mask_bit & lq_sta->active_legacy_rate; - lq_sta->last_txrate_idx = 4; - for (i = start_rate; i < count; i++) - if (mask_bit & BIT(i)) - lq_sta->last_txrate_idx = i; + /* Set last_txrate_idx to lowest rate */ + lq_sta->last_txrate_idx = rate_lowest_index(sband, sta); + if (sband->band == IEEE80211_BAND_5GHZ) + lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; rs_initialize_lq(priv, conf, sta, lq_sta); } @@ -2963,7 +2924,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (is_siso(tbl->lq_type)) ? "SISO" : ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); desc += sprintf(buff+desc, " %s", - (tbl->is_fat) ? "40MHz" : "20MHz"); + (tbl->is_ht40) ? "40MHz" : "20MHz"); desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "", (lq_sta->is_green) ? "GF enabled" : ""); } @@ -3028,12 +2989,13 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, return -ENOMEM; for (i = 0; i < LQ_SIZE; i++) { - desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n" + desc += sprintf(buff+desc, + "%s type=%d SGI=%d HT40=%d DUP=%d GF=%d\n" "rate=0x%X\n", lq_sta->active_tbl == i ? "*" : "x", lq_sta->lq_info[i].lq_type, lq_sta->lq_info[i].is_SGI, - lq_sta->lq_info[i].is_fat, + lq_sta->lq_info[i].is_ht40, lq_sta->lq_info[i].is_dup, lq_sta->is_green, lq_sta->lq_info[i].current_rate); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 25050bf315a..9fac530cfb7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -73,6 +73,7 @@ enum { IWL_RATE_54M_INDEX, IWL_RATE_60M_INDEX, IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ + IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */ IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1, IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, IWL_RATE_INVALID = IWL_RATE_COUNT, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index db580cbf598..00457bff1ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -533,16 +533,12 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, if (palive->ver_subtype == INITIALIZE_SUBTYPE) { IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); memcpy(&priv->card_alive_init, &pkt->u.alive_frame, sizeof(struct iwl_init_alive_resp)); pwork = &priv->init_alive_start; } else { IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - set_bit(STATUS_RT_UCODE_ALIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); memcpy(&priv->card_alive, &pkt->u.alive_frame, sizeof(struct iwl_alive_resp)); pwork = &priv->alive_start; @@ -896,7 +892,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { + if (iwl_get_debug_level(priv) & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -931,7 +927,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -1045,7 +1041,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -1076,7 +1072,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) inta = priv->inta; #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { + if (iwl_get_debug_level(priv) & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", @@ -1104,7 +1100,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -1610,7 +1606,7 @@ static void iwl_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); - iwl_power_update_mode(priv, 1); + iwl_power_update_mode(priv, true); /* reassociate for ADHOC mode */ if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { @@ -1784,7 +1780,6 @@ static int __iwl_up(struct iwl_priv *priv) { int i; int ret; - unsigned long status; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); @@ -1862,51 +1857,6 @@ static int __iwl_up(struct iwl_priv *priv) /* start card; "initialize" will load runtime ucode */ iwl_nic_start(priv); - /* Just finish download Init or Runtime uCode image to device - * now we wait here for uCode send REPLY_ALIVE notification - * to indicate uCode is ready. - * 1) For Init uCode image, all iwlagn devices should wait here - * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before - * receive the REPLY_ALIVE notification, go back and try to - * download the Init uCode image again. - * 2) For Runtime uCode image, all iwlagn devices except 4965 - * wait here on STATUS_RT_UCODE_ALIVE status bit; if - * timeout before receive the REPLY_ALIVE notification, go back - * and download the Runtime uCode image again. - * 3) For 4965 Runtime uCode, it will not go through this path, - * need to wait for STATUS_RT_UCODE_ALIVE status bit in - * iwl4965_init_alive_start() function; if timeout, need to - * restart and download Init uCode image. - */ - if (priv->ucode_type == UCODE_INIT) - status = STATUS_INIT_UCODE_ALIVE; - else - status = STATUS_RT_UCODE_ALIVE; - if (test_bit(status, &priv->status)) { - IWL_WARN(priv, - "%s uCode already alive? " - "Waiting for alive anyway\n", - (status == STATUS_INIT_UCODE_ALIVE) - ? "INIT" : "Runtime"); - clear_bit(status, &priv->status); - } - ret = wait_event_interruptible_timeout( - priv->wait_command_queue, - test_bit(status, &priv->status), - UCODE_ALIVE_TIMEOUT); - if (!ret) { - if (!test_bit(status, &priv->status)) { - priv->ucode_type = - (status == STATUS_INIT_UCODE_ALIVE) - ? UCODE_NONE : UCODE_INIT; - IWL_ERR(priv, - "%s timeout after %dms\n", - (status == STATUS_INIT_UCODE_ALIVE) - ? "INIT" : "Runtime", - jiffies_to_msecs(UCODE_ALIVE_TIMEOUT)); - continue; - } - } IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); return 0; @@ -2125,7 +2075,7 @@ void iwl_post_associate(struct iwl_priv *priv) * If chain noise has already been run, then we need to enable * power management here */ if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) - iwl_power_update_mode(priv, 0); + iwl_power_update_mode(priv, false); /* Enable Rx differential gain and sensitivity calibrations */ iwl_chain_noise_reset(priv); @@ -2205,7 +2155,7 @@ static void iwl_mac_stop(struct ieee80211_hw *hw) priv->is_open = 0; - if (iwl_is_ready_rf(priv)) { + if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) { /* stop mac, cancel any scan request and clear * RXON_FILTER_ASSOC_MSK BIT */ @@ -2455,15 +2405,15 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, * * See the level definitions in iwl for details. * - * FIXME This file can be deprecated as the module parameter is - * writable and users can thus also change the debug level - * using the /sys/module/iwl3945/parameters/debug file. + * The debug_level being managed using sysfs below is a per device debug + * level that is used instead of the global debug level if it (the per + * device debug level) is set. */ - static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - return sprintf(buf, "0x%08X\n", iwl_debug_level); + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); } static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, @@ -2476,9 +2426,12 @@ static ssize_t store_debug_level(struct device *d, ret = strict_strtoul(buf, 0, &val); if (ret) IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); - else - iwl_debug_level = val; - + else { + priv->debug_level = val; + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, + "Not enough memory to generate traffic log\n"); + } return strnlen(buf, count); } @@ -2524,10 +2477,15 @@ static ssize_t store_tx_power(struct device *d, ret = strict_strtoul(buf, 10, &val); if (ret) IWL_INFO(priv, "%s is not in decimal form.\n", buf); - else - iwl_set_tx_power(priv, val, false); - - return count; + else { + ret = iwl_set_tx_power(priv, val, false); + if (ret) + IWL_ERR(priv, "failed setting tx power (0x%d).\n", + ret); + else + ret = count; + } + return ret; } static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); @@ -2612,47 +2570,6 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -static ssize_t store_power_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int ret; - unsigned long mode; - - - mutex_lock(&priv->mutex); - - ret = strict_strtoul(buf, 10, &mode); - if (ret) - goto out; - - ret = iwl_power_set_user_mode(priv, mode); - if (ret) { - IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n"); - goto out; - } - ret = count; - - out: - mutex_unlock(&priv->mutex); - return ret; -} - -static ssize_t show_power_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int level = priv->power_data.power_mode; - char *p = buf; - - p += sprintf(p, "%d\n", level); - return p - buf + 1; -} - -static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, - store_power_level); - static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) @@ -2745,7 +2662,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) static struct attribute *iwl_sysfs_entries[] = { &dev_attr_flags.attr, &dev_attr_filter_flags.attr, - &dev_attr_power_level.attr, &dev_attr_statistics.attr, &dev_attr_temperature.attr, &dev_attr_tx_power.attr, @@ -2819,6 +2735,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef CONFIG_IWLWIFI_DEBUG atomic_set(&priv->restrict_refcnt, 0); #endif + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, "Not enough memory to generate traffic log\n"); /************************** * 2. Initializing PCI bus @@ -3003,6 +2921,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_disable_device(pdev); out_ieee80211_free_hw: ieee80211_free_hw(priv->hw); + iwl_free_traffic_mem(priv); out: return err; } @@ -3061,6 +2980,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) * until now... */ destroy_workqueue(priv->workqueue); priv->workqueue = NULL; + iwl_free_traffic_mem(priv); free_irq(priv->pci_dev->irq, priv); pci_disable_msi(priv->pci_dev); diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 13180d6ee2f..c4b565a2de9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -852,7 +852,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, priv->cfg->ops->lib->update_chain_flags(priv); data->state = IWL_CHAIN_NOISE_DONE; - iwl_power_update_mode(priv, 0); + iwl_power_update_mode(priv, false); } EXPORT_SYMBOL(iwl_chain_noise_calibration); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 39ede5727fe..2c5c88fc38f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -283,7 +283,7 @@ struct iwl3945_power_per_rate { * 1) Dual stream (MIMO) * 2) Triple stream (MIMO) * - * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data + * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data * * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"): * 3-0: 0xD) 6 Mbps @@ -320,11 +320,11 @@ struct iwl3945_power_per_rate { #define RATE_MCS_GF_POS 10 #define RATE_MCS_GF_MSK 0x400 -/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */ -#define RATE_MCS_FAT_POS 11 -#define RATE_MCS_FAT_MSK 0x800 +/* Bit 11: (1) Use 40Mhz HT40 chnl width, (0) use 20 MHz legacy chnl width */ +#define RATE_MCS_HT40_POS 11 +#define RATE_MCS_HT40_MSK 0x800 -/* Bit 12: (1) Duplicate data on both 20MHz chnls. FAT (bit 11) must be set. */ +/* Bit 12: (1) Duplicate data on both 20MHz chnls. HT40 (bit 11) must be set. */ #define RATE_MCS_DUP_POS 12 #define RATE_MCS_DUP_MSK 0x1000 @@ -459,7 +459,7 @@ struct iwl_init_alive_resp { /* calibration values from "initialize" uCode */ __le32 voltage; /* signed, higher value is lower voltage */ - __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for FAT channel*/ + __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */ __le32 therm_r2[2]; /* signed */ __le32 therm_r3[2]; /* signed */ __le32 therm_r4[2]; /* signed */ @@ -610,7 +610,7 @@ enum { #define RXON_FLG_HT_OPERATING_MODE_POS (23) #define RXON_FLG_HT_PROT_MSK cpu_to_le32(0x1 << 23) -#define RXON_FLG_FAT_PROT_MSK cpu_to_le32(0x2 << 23) +#define RXON_FLG_HT40_PROT_MSK cpu_to_le32(0x2 << 23) #define RXON_FLG_CHANNEL_MODE_POS (25) #define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) @@ -886,12 +886,11 @@ struct iwl_qosparam_cmd { #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2); #define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); -#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); #define STA_FLG_RTS_MIMO_PROT_MSK cpu_to_le32(1 << 17) #define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18) #define STA_FLG_MAX_AGG_SIZE_POS (19) #define STA_FLG_MAX_AGG_SIZE_MSK cpu_to_le32(3 << 19) -#define STA_FLG_FAT_EN_MSK cpu_to_le32(1 << 21) +#define STA_FLG_HT40_EN_MSK cpu_to_le32(1 << 21) #define STA_FLG_MIMO_DIS_MSK cpu_to_le32(1 << 22) #define STA_FLG_AGG_MPDU_DENSITY_POS (23) #define STA_FLG_AGG_MPDU_DENSITY_MSK cpu_to_le32(7 << 23) @@ -1156,6 +1155,7 @@ struct iwl_wep_cmd { #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) #define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0) +#define RX_RES_PHY_FLAGS_ANTENNA_POS 4 #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) @@ -1984,10 +1984,10 @@ struct iwl_link_qual_agg_params { * a) Use this same initial rate for first 3 entries. * b) Find next lower available rate using same mode (SISO or MIMO), * use for next 3 entries. If no lower rate available, switch to - * legacy mode (no FAT channel, no MIMO, no short guard interval). + * legacy mode (no HT40 channel, no MIMO, no short guard interval). * c) If using MIMO, set command's mimo_delimiter to number of entries * using MIMO (3 or 6). - * d) After trying 2 HT rates, switch to legacy mode (no FAT channel, + * d) After trying 2 HT rates, switch to legacy mode (no HT40 channel, * no MIMO, no short guard interval), at the next lower bit rate * (e.g. if second HT bit rate was 54, try 48 legacy), and follow * legacy procedure for remaining table entries. @@ -2313,15 +2313,22 @@ struct iwl_spectrum_notification { * PM allow: * bit 0 - '0' Driver not allow power management * '1' Driver allow PM (use rest of parameters) + * * uCode send sleep notifications: * bit 1 - '0' Don't send sleep notification * '1' send sleep notification (SEND_PM_NOTIFICATION) + * * Sleep over DTIM * bit 2 - '0' PM have to walk up every DTIM * '1' PM could sleep over DTIM till listen Interval. + * * PCI power managed * bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1) * '1' !(PCI_CFG_LINK_CTRL & 0x1) + * + * Fast PD + * bit 4 - '1' Put radio to sleep when receiving frame for others + * * Force sleep Modes * bit 31/30- '00' use both mac/xtal sleeps * '01' force Mac sleep @@ -2922,6 +2929,20 @@ struct statistics_rx { struct statistics_rx_ht_phy ofdm_ht; } __attribute__ ((packed)); +/** + * struct statistics_tx_power - current tx power + * + * @ant_a: current tx power on chain a in 1/2 dB step + * @ant_b: current tx power on chain b in 1/2 dB step + * @ant_c: current tx power on chain c in 1/2 dB step + */ +struct statistics_tx_power { + u8 ant_a; + u8 ant_b; + u8 ant_c; + u8 reserved; +} __attribute__ ((packed)); + struct statistics_tx_non_phy_agg { __le32 ba_timeout; __le32 ba_reschedule_frames; @@ -2933,8 +2954,6 @@ struct statistics_tx_non_phy_agg { __le32 underrun; __le32 bt_prio_kill; __le32 rx_ba_rsp_cnt; - __le32 reserved2; - __le32 reserved3; } __attribute__ ((packed)); struct statistics_tx { @@ -2953,6 +2972,8 @@ struct statistics_tx { __le32 cts_timeout_collision; __le32 ack_or_ba_timeout_collision; struct statistics_tx_non_phy_agg agg; + struct statistics_tx_power tx_power; + __le32 reserved1; } __attribute__ ((packed)); @@ -3017,7 +3038,7 @@ struct iwl_statistics_cmd { * one channel that has just been scanned. */ #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) -#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8) +#define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8) struct iwl3945_notif_statistics { __le32 flag; @@ -3474,7 +3495,7 @@ struct iwl_wimax_coex_cmd { *****************************************************************************/ struct iwl_rx_packet { - __le32 len; + __le32 len_n_flags; struct iwl_cmd_header hdr; union { struct iwl3945_rx_frame rx_frame; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6797076bd45..acfd7b40afb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -96,7 +96,6 @@ EXPORT_SYMBOL(iwl_rates); void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, struct ieee80211_tx_info *info) { - int rate_index; struct ieee80211_tx_rate *r = &info->control.rates[0]; info->antenna_sel_tx = @@ -105,16 +104,13 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, r->flags |= IEEE80211_TX_RC_MCS; if (rate_n_flags & RATE_MCS_GF_MSK) r->flags |= IEEE80211_TX_RC_GREEN_FIELD; - if (rate_n_flags & RATE_MCS_FAT_MSK) + if (rate_n_flags & RATE_MCS_HT40_MSK) r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (rate_n_flags & RATE_MCS_DUP_MSK) r->flags |= IEEE80211_TX_RC_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) r->flags |= IEEE80211_TX_RC_SHORT_GI; - rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags); - if (info->band == IEEE80211_BAND_5GHZ) - rate_index -= IWL_FIRST_OFDM_RATE; - r->idx = rate_index; + r->idx = iwl_hwrate_to_mac80211_idx(rate_n_flags, info->band); } EXPORT_SYMBOL(iwl_hwrate_to_tx_control); @@ -149,6 +145,27 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) } EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx); +int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band) +{ + int idx = 0; + int band_offset = 0; + + /* HT rate format: mac80211 wants an MCS number, which is just LSB */ + if (rate_n_flags & RATE_MCS_HT_MSK) { + idx = (rate_n_flags & 0xff); + return idx; + /* Legacy rate format, search for match in table */ + } else { + if (band == IEEE80211_BAND_5GHZ) + band_offset = IWL_FIRST_OFDM_RATE; + for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) + if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) + return idx - band_offset; + } + + return -1; +} + u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant) { int i; @@ -394,13 +411,14 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->ht_supported = true; - ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + if (priv->cfg->ht_greenfield_support) + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= IEEE80211_HT_CAP_SGI_20; ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & (WLAN_HT_CAP_SM_PS_DISABLED << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; - if (priv->hw_params.fat_channel & BIT(band)) { + if (priv->hw_params.ht40_channel & BIT(band)) { ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; ht_info->cap |= IEEE80211_HT_CAP_SGI_40; ht_info->mcs.rx_mask[4] = 0x01; @@ -438,12 +456,12 @@ static void iwlcore_init_hw_rates(struct iwl_priv *priv, { int i; - for (i = 0; i < IWL_RATE_COUNT; i++) { + for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) { rates[i].bitrate = iwl_rates[i].ieee * 5; rates[i].hw_value = i; /* Rate scaling will work on indexes */ rates[i].hw_value_short = i; rates[i].flags = 0; - if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { + if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) { /* * If CCK != 1M then set short preamble rate flag. */ @@ -479,7 +497,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) if (!channels) return -ENOMEM; - rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), + rates = kzalloc((sizeof(struct ieee80211_rate) * IWL_RATE_COUNT_LEGACY), GFP_KERNEL); if (!rates) { kfree(channels); @@ -491,7 +509,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; /* just OFDM */ sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; - sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; + sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE; if (priv->cfg->sku & IWL_SKU_N) iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, @@ -501,7 +519,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) sband->channels = channels; /* OFDM & CCK */ sband->bitrates = rates; - sband->n_bitrates = IWL_RATE_COUNT; + sband->n_bitrates = IWL_RATE_COUNT_LEGACY; if (priv->cfg->sku & IWL_SKU_N) iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, @@ -540,10 +558,10 @@ int iwlcore_init_geos(struct iwl_priv *priv) if (ch->flags & EEPROM_CHANNEL_RADAR) geo_ch->flags |= IEEE80211_CHAN_RADAR; - geo_ch->flags |= ch->fat_extension_channel; + geo_ch->flags |= ch->ht40_extension_channel; - if (ch->max_power_avg > priv->tx_power_channel_lmt) - priv->tx_power_channel_lmt = ch->max_power_avg; + if (ch->max_power_avg > priv->tx_power_device_lmt) + priv->tx_power_device_lmt = ch->max_power_avg; } else { geo_ch->flags |= IEEE80211_CHAN_DISABLED; } @@ -604,16 +622,16 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, return 0; if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) - return !(ch_info->fat_extension_channel & + return !(ch_info->ht40_extension_channel & IEEE80211_CHAN_NO_HT40PLUS); else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) - return !(ch_info->fat_extension_channel & + return !(ch_info->ht40_extension_channel & IEEE80211_CHAN_NO_HT40MINUS); return 0; } -u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, +u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, struct ieee80211_sta_ht_cap *sta_ht_inf) { struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; @@ -637,7 +655,7 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, le16_to_cpu(priv->staging_rxon.channel), iwl_ht_conf->extension_chan_offset); } -EXPORT_SYMBOL(iwl_is_fat_tx_allowed); +EXPORT_SYMBOL(iwl_is_ht40_tx_allowed); static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) { @@ -866,7 +884,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) if (!ht_info->is_ht) { rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | - RXON_FLG_FAT_PROT_MSK | + RXON_FLG_HT40_PROT_MSK | RXON_FLG_HT_PROT_MSK); return; } @@ -877,12 +895,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); /* Set up channel bandwidth: - * 20 MHz only, 20/40 mixed or pure 40 if fat ok */ + * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ /* clear the HT channel mode before set the mode */ rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); - if (iwl_is_fat_tx_allowed(priv, NULL)) { - /* pure 40 fat */ + if (iwl_is_ht40_tx_allowed(priv, NULL)) { + /* pure ht40 */ if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; /* Note: control channel is opposite of extension channel */ @@ -1230,7 +1248,7 @@ static void iwl_set_rate(struct iwl_priv *priv) for (i = 0; i < hw->n_bitrates; i++) { rate = &(hw->bitrates[i]); - if (rate->hw_value < IWL_RATE_COUNT) + if (rate->hw_value < IWL_RATE_COUNT_LEGACY) priv->active_rate |= (1 << rate->hw_value); } @@ -1278,7 +1296,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) struct iwl_rxon_cmd *rxon = &priv->staging_rxon; IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); - iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n", @@ -1343,17 +1361,10 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; - switch (priv->ucode_type) { - case UCODE_RT: - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); - break; - case UCODE_INIT: + if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - break; - default: - IWL_ERR(priv, "uCode image not available\n"); - return; - } + else + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); @@ -1405,17 +1416,10 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, if (num_events == 0) return; - switch (priv->ucode_type) { - case UCODE_RT: - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - break; - case UCODE_INIT: + if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - break; - default: - IWL_ERR(priv, "uCode image not available\n"); - return; - } + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (mode == 0) event_size = 2 * sizeof(u32); @@ -1452,17 +1456,10 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ - switch (priv->ucode_type) { - case UCODE_RT: - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - break; - case UCODE_INIT: + if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); - break; - default: - IWL_ERR(priv, "uCode image not available\n"); - return; - } + else + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); @@ -1508,7 +1505,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_FW_ERRORS) { + if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) { iwl_dump_nic_error_log(priv); iwl_dump_nic_event_log(priv); iwl_print_rx_config_cmd(priv); @@ -1534,7 +1531,7 @@ EXPORT_SYMBOL(iwl_irq_handle_error); void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list) + u64 multicast) { struct iwl_priv *priv = hw->priv; __le32 *filter_flags = &priv->staging_rxon.filter_flags; @@ -1589,13 +1586,23 @@ int iwl_setup_mac(struct iwl_priv *priv) IEEE80211_HW_NOISE_DBM | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_SUPPORTS_PS; + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->custom_regulatory = true; + /* Firmware does not support this */ + hw->wiphy->disable_beacon_hints = true; + + /* + * For now, disable PS by default because it affects + * RX performance significantly. + */ + hw->wiphy->ps_default = false; + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; /* we create the 802.11 header and a zero-length SSID element */ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; @@ -1681,9 +1688,10 @@ int iwl_init_drv(struct iwl_priv *priv) priv->qos_data.qos_cap.val = 0; priv->rates_mask = IWL_RATES_MASK; - /* If power management is turned on, default to CAM mode */ - priv->power_mode = IWL_POWER_MODE_CAM; - priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; + /* Set the tx_power_user_lmt to the lowest power level + * this value will get overwritten by channel max power avg + * from eeprom */ + priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MIN; ret = iwl_init_channel_map(priv); if (ret) { @@ -1710,6 +1718,8 @@ EXPORT_SYMBOL(iwl_init_drv); int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret = 0; + s8 prev_tx_power = priv->tx_power_user_lmt; + if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) { IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n", tx_power, @@ -1717,25 +1727,37 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) return -EINVAL; } - if (tx_power > IWL_TX_POWER_TARGET_POWER_MAX) { - IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n", - tx_power, - IWL_TX_POWER_TARGET_POWER_MAX); + if (tx_power > priv->tx_power_device_lmt) { + IWL_WARN(priv, + "Requested user TXPOWER %d above upper limit %d.\n", + tx_power, priv->tx_power_device_lmt); return -EINVAL; } if (priv->tx_power_user_lmt != tx_power) force = true; - priv->tx_power_user_lmt = tx_power; - /* if nic is not up don't send command */ - if (!iwl_is_ready_rf(priv)) - return ret; - - if (force && priv->cfg->ops->lib->send_tx_power) - ret = priv->cfg->ops->lib->send_tx_power(priv); + if (iwl_is_ready_rf(priv)) { + priv->tx_power_user_lmt = tx_power; + if (force && priv->cfg->ops->lib->send_tx_power) + ret = priv->cfg->ops->lib->send_tx_power(priv); + else if (!priv->cfg->ops->lib->send_tx_power) + ret = -EOPNOTSUPP; + /* + * if fail to set tx_power, restore the orig. tx power + */ + if (ret) + priv->tx_power_user_lmt = prev_tx_power; + } + /* + * Even this is an async host command, the command + * will always report success from uCode + * So once driver can placing the command into the queue + * successfully, driver can use priv->tx_power_user_lmt + * to reflect the current tx power + */ return ret; } EXPORT_SYMBOL(iwl_set_tx_power); @@ -1818,7 +1840,7 @@ int iwl_reset_ict(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); iwl_disable_interrupts(priv); - memset(&priv->ict_tbl[0],0, sizeof(u32) * ICT_COUNT); + memset(&priv->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT); val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT; @@ -1896,13 +1918,13 @@ irqreturn_t iwl_isr_ict(int irq, void *data) /* read all entries that not 0 start with ict_index */ while (priv->ict_tbl[priv->ict_index]) { - val |= priv->ict_tbl[priv->ict_index]; + val |= le32_to_cpu(priv->ict_tbl[priv->ict_index]); IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n", - priv->ict_index, - priv->ict_tbl[priv->ict_index]); + priv->ict_index, + le32_to_cpu(priv->ict_tbl[priv->ict_index])); priv->ict_tbl[priv->ict_index] = 0; priv->ict_index = iwl_queue_inc_wrap(priv->ict_index, - ICT_COUNT); + ICT_COUNT); } @@ -1982,7 +2004,7 @@ static irqreturn_t iwl_isr(int irq, void *data) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " "fh 0x%08x\n", inta, inta_mask, inta_fh); @@ -2232,7 +2254,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); - priv->power_data.ct_kill_toggle = false; + priv->thermal_throttle.ct_kill_toggle = false; switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_1000: @@ -2245,6 +2267,15 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(adv_cmd), &adv_cmd); + if (ret) + IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); + else + IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " + "succeeded, " + "critical temperature enter is %d," + "exit is %d\n", + priv->hw_params.ct_kill_threshold, + priv->hw_params.ct_kill_exit_threshold); break; default: cmd.critical_temperature_R = @@ -2252,16 +2283,15 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); + if (ret) + IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); + else + IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " + "succeeded, " + "critical temperature is %d\n", + priv->hw_params.ct_kill_threshold); break; } - ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); - else - IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD succeeded, " - "critical temperature is %d\n", - cmd.critical_temperature_R); } EXPORT_SYMBOL(iwl_rf_kill_ct_config); @@ -2304,10 +2334,11 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " - "notification for %s:\n", - le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + "notification for %s:\n", len, + get_cmd_string(pkt->hdr.cmd)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len); } EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); @@ -2402,39 +2433,10 @@ static void iwl_ht_conf(struct iwl_priv *priv, } ht_conf = &sta->ht_cap; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) - iwl_conf->sgf |= HT_SHORT_GI_20MHZ; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) - iwl_conf->sgf |= HT_SHORT_GI_40MHZ; - - iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->max_amsdu_size = - !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); - - iwl_conf->supported_chan_width = - !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); - - /* - * XXX: The HT configuration needs to be moved into iwl_mac_config() - * to be done there correctly. - */ - - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; - if (conf_is_ht40_minus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; - else if (conf_is_ht40_plus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - - /* If no above or below channel supplied disable FAT channel */ - if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && - iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) - iwl_conf->supported_chan_width = 0; - iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); - iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; iwl_conf->ht_protection = bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; iwl_conf->non_GF_STA_present = @@ -2561,7 +2563,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, if (bss_conf->assoc) { priv->assoc_id = bss_conf->aid; priv->beacon_int = bss_conf->beacon_int; - priv->power_data.dtim_period = bss_conf->dtim_period; priv->timestamp = bss_conf->timestamp; priv->assoc_capability = bss_conf->assoc_capability; @@ -2748,6 +2749,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; struct ieee80211_conf *conf = &hw->conf; + struct iwl_ht_info *ht_conf = &priv->current_ht_config; unsigned long flags = 0; int ret = 0; u16 ch; @@ -2789,10 +2791,32 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) goto set_ch_out; } - priv->current_ht_config.is_ht = conf_is_ht(conf); - spin_lock_irqsave(&priv->lock, flags); + /* Configure HT40 channels */ + ht_conf->is_ht = conf_is_ht(conf); + if (ht_conf->is_ht) { + if (conf_is_ht40_minus(conf)) { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_40MHZ; + } else if (conf_is_ht40_plus(conf)) { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_40MHZ; + } else { + ht_conf->extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ht_conf->supported_chan_width = + IWL_CHANNEL_WIDTH_20MHZ; + } + } else + ht_conf->supported_chan_width = IWL_CHANNEL_WIDTH_20MHZ; + /* Default to no protection. Protection mode will later be set + * from BSS config in iwl_ht_conf */ + ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; /* if we are switching from ht to 2.4 clear flags * from any ht related info since 2.4 does not @@ -2811,13 +2835,10 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) iwl_set_rate(priv); } - if (changed & IEEE80211_CONF_CHANGE_PS && - priv->iw_mode == NL80211_IFTYPE_STATION) { - priv->power_data.power_disabled = - !(conf->flags & IEEE80211_CONF_PS); - ret = iwl_power_update_mode(priv, 0); + if (changed & IEEE80211_CONF_CHANGE_PS) { + ret = iwl_power_update_mode(priv, false); if (ret) - IWL_DEBUG_MAC80211(priv, "Error setting power level\n"); + IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); } if (changed & IEEE80211_CONF_CHANGE_POWER) { @@ -2950,6 +2971,248 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) } EXPORT_SYMBOL(iwl_mac_reset_tsf); +#ifdef CONFIG_IWLWIFI_DEBUGFS + +#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES) + +void iwl_reset_traffic_log(struct iwl_priv *priv) +{ + priv->tx_traffic_idx = 0; + priv->rx_traffic_idx = 0; + if (priv->tx_traffic) + memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); + if (priv->rx_traffic) + memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); +} + +int iwl_alloc_traffic_mem(struct iwl_priv *priv) +{ + u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE; + + if (iwl_debug_level & IWL_DL_TX) { + if (!priv->tx_traffic) { + priv->tx_traffic = + kzalloc(traffic_size, GFP_KERNEL); + if (!priv->tx_traffic) + return -ENOMEM; + } + } + if (iwl_debug_level & IWL_DL_RX) { + if (!priv->rx_traffic) { + priv->rx_traffic = + kzalloc(traffic_size, GFP_KERNEL); + if (!priv->rx_traffic) + return -ENOMEM; + } + } + iwl_reset_traffic_log(priv); + return 0; +} +EXPORT_SYMBOL(iwl_alloc_traffic_mem); + +void iwl_free_traffic_mem(struct iwl_priv *priv) +{ + kfree(priv->tx_traffic); + priv->tx_traffic = NULL; + + kfree(priv->rx_traffic); + priv->rx_traffic = NULL; +} +EXPORT_SYMBOL(iwl_free_traffic_mem); + +void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ + __le16 fc; + u16 len; + + if (likely(!(iwl_debug_level & IWL_DL_TX))) + return; + + if (!priv->tx_traffic) + return; + + fc = header->frame_control; + if (ieee80211_is_data(fc)) { + len = (length > IWL_TRAFFIC_ENTRY_SIZE) + ? IWL_TRAFFIC_ENTRY_SIZE : length; + memcpy((priv->tx_traffic + + (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), + header, len); + priv->tx_traffic_idx = + (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; + } +} +EXPORT_SYMBOL(iwl_dbg_log_tx_data_frame); + +void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ + __le16 fc; + u16 len; + + if (likely(!(iwl_debug_level & IWL_DL_RX))) + return; + + if (!priv->rx_traffic) + return; + + fc = header->frame_control; + if (ieee80211_is_data(fc)) { + len = (length > IWL_TRAFFIC_ENTRY_SIZE) + ? IWL_TRAFFIC_ENTRY_SIZE : length; + memcpy((priv->rx_traffic + + (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), + header, len); + priv->rx_traffic_idx = + (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; + } +} +EXPORT_SYMBOL(iwl_dbg_log_rx_data_frame); + +const char *get_mgmt_string(int cmd) +{ + switch (cmd) { + IWL_CMD(MANAGEMENT_ASSOC_REQ); + IWL_CMD(MANAGEMENT_ASSOC_RESP); + IWL_CMD(MANAGEMENT_REASSOC_REQ); + IWL_CMD(MANAGEMENT_REASSOC_RESP); + IWL_CMD(MANAGEMENT_PROBE_REQ); + IWL_CMD(MANAGEMENT_PROBE_RESP); + IWL_CMD(MANAGEMENT_BEACON); + IWL_CMD(MANAGEMENT_ATIM); + IWL_CMD(MANAGEMENT_DISASSOC); + IWL_CMD(MANAGEMENT_AUTH); + IWL_CMD(MANAGEMENT_DEAUTH); + IWL_CMD(MANAGEMENT_ACTION); + default: + return "UNKNOWN"; + + } +} + +const char *get_ctrl_string(int cmd) +{ + switch (cmd) { + IWL_CMD(CONTROL_BACK_REQ); + IWL_CMD(CONTROL_BACK); + IWL_CMD(CONTROL_PSPOLL); + IWL_CMD(CONTROL_RTS); + IWL_CMD(CONTROL_CTS); + IWL_CMD(CONTROL_ACK); + IWL_CMD(CONTROL_CFEND); + IWL_CMD(CONTROL_CFENDACK); + default: + return "UNKNOWN"; + + } +} + +void iwl_clear_tx_stats(struct iwl_priv *priv) +{ + memset(&priv->tx_stats, 0, sizeof(struct traffic_stats)); + +} + +void iwl_clear_rx_stats(struct iwl_priv *priv) +{ + memset(&priv->rx_stats, 0, sizeof(struct traffic_stats)); +} + +/* + * if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will + * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass. + * Use debugFs to display the rx/rx_statistics + * if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL + * information will be recorded, but DATA pkt still will be recorded + * for the reason of iwl_led.c need to control the led blinking based on + * number of tx and rx data. + * + */ +void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) +{ + struct traffic_stats *stats; + + if (is_tx) + stats = &priv->tx_stats; + else + stats = &priv->rx_stats; + + if (ieee80211_is_mgmt(fc)) { + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): + stats->mgmt[MANAGEMENT_ASSOC_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): + stats->mgmt[MANAGEMENT_ASSOC_RESP]++; + break; + case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): + stats->mgmt[MANAGEMENT_REASSOC_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): + stats->mgmt[MANAGEMENT_REASSOC_RESP]++; + break; + case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): + stats->mgmt[MANAGEMENT_PROBE_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): + stats->mgmt[MANAGEMENT_PROBE_RESP]++; + break; + case cpu_to_le16(IEEE80211_STYPE_BEACON): + stats->mgmt[MANAGEMENT_BEACON]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ATIM): + stats->mgmt[MANAGEMENT_ATIM]++; + break; + case cpu_to_le16(IEEE80211_STYPE_DISASSOC): + stats->mgmt[MANAGEMENT_DISASSOC]++; + break; + case cpu_to_le16(IEEE80211_STYPE_AUTH): + stats->mgmt[MANAGEMENT_AUTH]++; + break; + case cpu_to_le16(IEEE80211_STYPE_DEAUTH): + stats->mgmt[MANAGEMENT_DEAUTH]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ACTION): + stats->mgmt[MANAGEMENT_ACTION]++; + break; + } + } else if (ieee80211_is_ctl(fc)) { + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_BACK_REQ): + stats->ctrl[CONTROL_BACK_REQ]++; + break; + case cpu_to_le16(IEEE80211_STYPE_BACK): + stats->ctrl[CONTROL_BACK]++; + break; + case cpu_to_le16(IEEE80211_STYPE_PSPOLL): + stats->ctrl[CONTROL_PSPOLL]++; + break; + case cpu_to_le16(IEEE80211_STYPE_RTS): + stats->ctrl[CONTROL_RTS]++; + break; + case cpu_to_le16(IEEE80211_STYPE_CTS): + stats->ctrl[CONTROL_CTS]++; + break; + case cpu_to_le16(IEEE80211_STYPE_ACK): + stats->ctrl[CONTROL_ACK]++; + break; + case cpu_to_le16(IEEE80211_STYPE_CFEND): + stats->ctrl[CONTROL_CFEND]++; + break; + case cpu_to_le16(IEEE80211_STYPE_CFENDACK): + stats->ctrl[CONTROL_CFENDACK]++; + break; + } + } else { + /* data */ + stats->data_cnt++; + stats->data_bytes += len; + } +} +EXPORT_SYMBOL(iwl_update_stats); +#endif + #ifdef CONFIG_PM int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 10ddcdda104..c04d2a27081 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -83,6 +83,8 @@ struct iwl_cmd; #define IWL_SKU_A 0x2 #define IWL_SKU_N 0x8 +#define IWL_CMD(x) case x: return #x + struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); int (*commit_rxon)(struct iwl_priv *priv); @@ -207,6 +209,8 @@ struct iwl_mod_params { * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. * @pa_type: used by 6000 series only to identify the type of Power Amplifier + * @max_ll_items: max number of OTP blocks + * @shadow_ram_support: shadow support for OTP memory * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -245,6 +249,9 @@ struct iwl_cfg { bool need_pll_cfg; bool use_isr_legacy; enum iwl_pa_type pa_type; + const u16 max_ll_items; + const bool shadow_ram_support; + const bool ht_greenfield_support; }; /*************************** @@ -264,7 +271,7 @@ int iwl_full_rxon_required(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); -u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, +u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, struct ieee80211_sta_ht_cap *sta_ht_inf); void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band); void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode); @@ -275,8 +282,7 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv, void iwl_irq_handle_error(struct iwl_priv *priv); void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list); + unsigned int *total_flags, u64 multicast); int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); @@ -300,7 +306,55 @@ void iwl_config_ap(struct iwl_priv *priv); int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); void iwl_mac_reset_tsf(struct ieee80211_hw *hw); +#ifdef CONFIG_IWLWIFI_DEBUGFS +int iwl_alloc_traffic_mem(struct iwl_priv *priv); +void iwl_free_traffic_mem(struct iwl_priv *priv); +void iwl_reset_traffic_log(struct iwl_priv *priv); +void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header); +void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header); +const char *get_mgmt_string(int cmd); +const char *get_ctrl_string(int cmd); +void iwl_clear_tx_stats(struct iwl_priv *priv); +void iwl_clear_rx_stats(struct iwl_priv *priv); +void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, + u16 len); +#else +static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv) +{ + return 0; +} +static inline void iwl_free_traffic_mem(struct iwl_priv *priv) +{ +} +static inline void iwl_reset_traffic_log(struct iwl_priv *priv) +{ +} +static inline void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ +} +static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, + u16 length, struct ieee80211_hdr *header) +{ +} +static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx, + __le16 fc, u16 len) +{ + struct traffic_stats *stats; + + if (is_tx) + stats = &priv->tx_stats; + else + stats = &priv->rx_stats; + if (ieee80211_is_data(fc)) { + /* data */ + stats->data_bytes += len; + } +} +#endif /***************************************************** * RX handlers. * **************************************************/ @@ -369,6 +423,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, struct ieee80211_tx_info *info); int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); +int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band); u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv); @@ -512,8 +567,6 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 #define STATUS_MODE_PENDING 18 -#define STATUS_INIT_UCODE_ALIVE 19 -#define STATUS_RT_UCODE_ALIVE 20 static inline int iwl_is_ready(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index fbe177608bc..cbc62904655 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -46,7 +46,7 @@ do { \ #ifdef CONFIG_IWLWIFI_DEBUG #define IWL_DEBUG(__priv, level, fmt, args...) \ do { \ - if (iwl_debug_level & (level)) \ + if (iwl_get_debug_level(__priv) & (level)) \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ @@ -54,15 +54,15 @@ do { \ #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \ do { \ - if ((iwl_debug_level & (level)) && net_ratelimit()) \ + if ((iwl_get_debug_level(__priv) & (level)) && net_ratelimit()) \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ } while (0) -#define iwl_print_hex_dump(level, p, len) \ +#define iwl_print_hex_dump(priv, level, p, len) \ do { \ - if (iwl_debug_level & level) \ + if (iwl_get_debug_level(priv) & level) \ print_hex_dump(KERN_DEBUG, "iwl data: ", \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) @@ -72,13 +72,12 @@ struct iwl_debugfs { const char *name; struct dentry *dir_drv; struct dentry *dir_data; + struct dentry *dir_debug; struct dentry *dir_rf; struct dir_data_files { struct dentry *file_sram; struct dentry *file_nvm; struct dentry *file_stations; - struct dentry *file_rx_statistics; - struct dentry *file_tx_statistics; struct dentry *file_log_event; struct dentry *file_channels; struct dentry *file_status; @@ -89,12 +88,27 @@ struct iwl_debugfs { struct dentry *file_led; #endif struct dentry *file_disable_ht40; + struct dentry *file_sleep_level_override; + struct dentry *file_current_sleep_command; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; struct dentry *file_disable_chain_noise; struct dentry *file_disable_tx_power; } dbgfs_rf_files; + struct dir_debug_files { + struct dentry *file_rx_statistics; + struct dentry *file_tx_statistics; + struct dentry *file_traffic_log; + struct dentry *file_rx_queue; + struct dentry *file_tx_queue; + struct dentry *file_ucode_rx_stats; + struct dentry *file_ucode_tx_stats; + struct dentry *file_ucode_general_stats; + struct dentry *file_sensitivity; + struct dentry *file_chain_noise; + struct dentry *file_tx_power; + } dbgfs_debug_files; u32 sram_offset; u32 sram_len; }; @@ -106,7 +120,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv); #else #define IWL_DEBUG(__priv, level, fmt, args...) #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) -static inline void iwl_print_hex_dump(int level, void *p, u32 len) +static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, + void *p, u32 len) {} #endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 7707a265599..fb844859a44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -38,7 +38,7 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" - +#include "iwl-calib.h" /* create and remove of files */ #define DEBUGFS_ADD_DIR(name, parent) do { \ @@ -126,18 +126,58 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - char buf[256]; + char *buf; int pos = 0; - const size_t bufsz = sizeof(buf); - pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n", - priv->tx_stats[0].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n", - priv->tx_stats[1].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n", - priv->tx_stats[2].cnt); + int cnt; + ssize_t ret; + const size_t bufsz = 100 + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); + for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_mgmt_string(cnt), + priv->tx_stats.mgmt[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Control\n"); + for (cnt = 0; cnt < CONTROL_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_ctrl_string(cnt), + priv->tx_stats.ctrl[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Data:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n", + priv->tx_stats.data_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n", + priv->tx_stats.data_bytes); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + u32 clear_flag; + char buf[8]; + int buf_size; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%x", &clear_flag) != 1) + return -EFAULT; + if (clear_flag == 1) + iwl_clear_tx_stats(priv); + + return count; } static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, @@ -145,18 +185,59 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - char buf[256]; + char *buf; int pos = 0; - const size_t bufsz = sizeof(buf); + int cnt; + ssize_t ret; + const size_t bufsz = 100 + + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; - pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n", - priv->rx_stats[0].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n", - priv->rx_stats[1].cnt); - pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n", - priv->rx_stats[2].cnt); + pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); + for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_mgmt_string(cnt), + priv->rx_stats.mgmt[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Control:\n"); + for (cnt = 0; cnt < CONTROL_MAX; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, + "\t%s\t\t: %u\n", + get_ctrl_string(cnt), + priv->rx_stats.ctrl[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "Data:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n", + priv->rx_stats.data_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n", + priv->rx_stats.data_bytes); - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_rx_statistics_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + u32 clear_flag; + char buf[8]; + int buf_size; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%x", &clear_flag) != 1) + return -EFAULT; + if (clear_flag == 1) + iwl_clear_rx_stats(priv); + return count; } #define BYTE1_MASK 0x000000ff; @@ -310,18 +391,18 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, return -ENODATA; } + ptr = priv->eeprom; + if (!ptr) { + IWL_ERR(priv, "Invalid EEPROM/OTP memory\n"); + return -ENOMEM; + } + /* 4 characters for byte 0xYY */ buf = kzalloc(buf_size, GFP_KERNEL); if (!buf) { IWL_ERR(priv, "Can not allocate Buffer\n"); return -ENOMEM; } - - ptr = priv->eeprom; - if (!ptr) { - IWL_ERR(priv, "Invalid EEPROM/OTP memory\n"); - return -ENOMEM; - } pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n", (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) ? "OTP" : "EEPROM"); @@ -623,7 +704,7 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; char buf[100]; int pos = 0; @@ -632,12 +713,11 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, "Thermal Throttling Mode: %s\n", - (priv->power_data.adv_tt) - ? "Advance" : "Legacy"); + tt->advanced_tt ? "Advance" : "Legacy"); pos += scnprintf(buf + pos, bufsz - pos, "Thermal Throttling State: %d\n", tt->state); - if (priv->power_data.adv_tt) { + if (tt->advanced_tt) { restriction = tt->restriction + tt->state; pos += scnprintf(buf + pos, bufsz - pos, "Tx mode: %d\n", @@ -696,12 +776,87 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int value; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + if (sscanf(buf, "%d", &value) != 1) + return -EINVAL; + + /* + * Our users expect 0 to be "CAM", but 0 isn't actually + * valid here. However, let's not confuse them and present + * IWL_POWER_INDEX_1 as "1", not "0". + */ + if (value > 0) + value -= 1; + + if (value != -1 && (value < 0 || value >= IWL_POWER_NUM)) + return -EINVAL; + + priv->power_data.debug_sleep_level_override = value; + + iwl_power_update_mode(priv, false); + + return count; +} + +static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[10]; + int pos, value; + const size_t bufsz = sizeof(buf); + + /* see the write function */ + value = priv->power_data.debug_sleep_level_override; + if (value >= 0) + value += 1; + + pos = scnprintf(buf, bufsz, "%d\n", value); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[200]; + int pos = 0, i; + const size_t bufsz = sizeof(buf); + struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd; + + pos += scnprintf(buf + pos, bufsz - pos, + "flags: %#.2x\n", le16_to_cpu(cmd->flags)); + pos += scnprintf(buf + pos, bufsz - pos, + "RX/TX timeout: %d/%d usec\n", + le32_to_cpu(cmd->rx_data_timeout), + le32_to_cpu(cmd->tx_data_timeout)); + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "sleep_interval[%d]: %d\n", i, + le32_to_cpu(cmd->sleep_interval[i])); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); DEBUGFS_READ_FILE_OPS(stations); -DEBUGFS_READ_FILE_OPS(rx_statistics); -DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_WRITE_FILE_OPS(interrupt); @@ -711,6 +866,765 @@ DEBUGFS_READ_FILE_OPS(led); #endif DEBUGFS_READ_FILE_OPS(thermal_throttling); DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); +DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); +DEBUGFS_READ_FILE_OPS(current_sleep_command); + +static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + int pos = 0, ofs = 0; + int cnt = 0, entry; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + struct iwl_rx_queue *rxq = &priv->rxq; + char *buf; + int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) + + (IWL_MAX_NUM_QUEUES * 32 * 8) + 400; + const u8 *ptr; + ssize_t ret; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate buffer\n"); + return -ENOMEM; + } + pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n"); + for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { + txq = &priv->txq[cnt]; + q = &txq->q; + pos += scnprintf(buf + pos, bufsz - pos, + "q[%d]: read_ptr: %u, write_ptr: %u\n", + cnt, q->read_ptr, q->write_ptr); + } + if (priv->tx_traffic && (iwl_debug_level & IWL_DL_TX)) { + ptr = priv->tx_traffic; + pos += scnprintf(buf + pos, bufsz - pos, + "Tx Traffic idx: %u\n", priv->tx_traffic_idx); + for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { + for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; + entry++, ofs += 16) { + pos += scnprintf(buf + pos, bufsz - pos, + "0x%.4x ", ofs); + hex_dump_to_buffer(ptr + ofs, 16, 16, 2, + buf + pos, bufsz - pos, 0); + pos += strlen(buf); + if (bufsz - pos > 0) + buf[pos++] = '\n'; + } + } + } + + pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "read: %u, write: %u\n", + rxq->read, rxq->write); + + if (priv->rx_traffic && (iwl_debug_level & IWL_DL_RX)) { + ptr = priv->rx_traffic; + pos += scnprintf(buf + pos, bufsz - pos, + "Rx Traffic idx: %u\n", priv->rx_traffic_idx); + for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { + for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; + entry++, ofs += 16) { + pos += scnprintf(buf + pos, bufsz - pos, + "0x%.4x ", ofs); + hex_dump_to_buffer(ptr + ofs, 16, 16, 2, + buf + pos, bufsz - pos, 0); + pos += strlen(buf); + if (bufsz - pos > 0) + buf[pos++] = '\n'; + } + } + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_traffic_log_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int traffic_log; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &traffic_log) != 1) + return -EFAULT; + if (traffic_log == 0) + iwl_reset_traffic_log(priv); + + return count; +} + +static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + char *buf; + int pos = 0; + int cnt; + int ret; + const size_t bufsz = sizeof(char) * 60 * IWL_MAX_NUM_QUEUES; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { + txq = &priv->txq[cnt]; + q = &txq->q; + pos += scnprintf(buf + pos, bufsz - pos, + "hwq %.2d: read=%u write=%u stop=%d" + " swq_id=%#.2x (ac %d/hwq %d)\n", + cnt, q->read_ptr, q->write_ptr, + !!test_bit(cnt, priv->queue_stopped), + txq->swq_id, + txq->swq_id & 0x80 ? txq->swq_id & 3 : + txq->swq_id, + txq->swq_id & 0x80 ? (txq->swq_id >> 2) & + 0x1f : txq->swq_id); + if (cnt >= 4) + continue; + /* for the ACs, display the stop count too */ + pos += scnprintf(buf + pos, bufsz - pos, + " stop-count: %d\n", + atomic_read(&priv->queue_stop_count[cnt])); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl_rx_queue *rxq = &priv->rxq; + char buf[256]; + int pos = 0; + const size_t bufsz = sizeof(buf); + + pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n", + rxq->read); + pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", + rxq->write); + pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n", + rxq->free_count); + pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n", + le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0) +#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1) +#define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2) + +static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, + int bufsz) +{ + int p = 0; + + p += scnprintf(buf + p, bufsz - p, + "Statistics Flag(0x%X):\n", + le32_to_cpu(priv->statistics.flag)); + if (le32_to_cpu(priv->statistics.flag) & UCODE_STATISTICS_CLEAR_MSK) + p += scnprintf(buf + p, bufsz - p, + "\tStatistics have been cleared\n"); + p += scnprintf(buf + p, bufsz - p, + "\tOperational Frequency: %s\n", + (le32_to_cpu(priv->statistics.flag) & + UCODE_STATISTICS_FREQUENCY_MSK) + ? "2.4 GHz" : "5.2 GHz"); + p += scnprintf(buf + p, bufsz - p, + "\tTGj Narrow Band: %s\n", + (le32_to_cpu(priv->statistics.flag) & + UCODE_STATISTICS_NARROW_BAND_MSK) + ? "enabled" : "disabled"); + return p; +} + + +static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_rx_phy) * 20 + + sizeof(struct statistics_rx_non_phy) * 20 + + sizeof(struct statistics_rx_ht_phy) * 20 + 400; + ssize_t ret; + struct statistics_rx_phy *ofdm; + struct statistics_rx_phy *cck; + struct statistics_rx_non_phy *general; + struct statistics_rx_ht_phy *ht; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + ofdm = &priv->statistics.rx.ofdm; + cck = &priv->statistics.rx.cck; + general = &priv->statistics.rx.general; + ht = &priv->statistics.rx.ofdm_ht; + pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n", + le32_to_cpu(ofdm->ina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n", + le32_to_cpu(ofdm->fina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", + le32_to_cpu(ofdm->plcp_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", + le32_to_cpu(ofdm->crc32_err)); + pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", + le32_to_cpu(ofdm->overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", + le32_to_cpu(ofdm->early_overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", + le32_to_cpu(ofdm->crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n", + le32_to_cpu(ofdm->false_alarm_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n", + le32_to_cpu(ofdm->fina_sync_err_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n", + le32_to_cpu(ofdm->sfd_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n", + le32_to_cpu(ofdm->fina_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n", + le32_to_cpu(ofdm->unresponded_rts)); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_limit_overrun: %u\n", + le32_to_cpu(ofdm->rxe_frame_limit_overrun)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", + le32_to_cpu(ofdm->sent_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", + le32_to_cpu(ofdm->sent_cts_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", + le32_to_cpu(ofdm->sent_ba_rsp_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", + le32_to_cpu(ofdm->dsp_self_kill)); + pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", + le32_to_cpu(ofdm->mh_format_err)); + pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", + le32_to_cpu(ofdm->re_acq_main_rssi_sum)); + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n", + le32_to_cpu(cck->ina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n", + le32_to_cpu(cck->fina_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", + le32_to_cpu(cck->plcp_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", + le32_to_cpu(cck->crc32_err)); + pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", + le32_to_cpu(cck->overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", + le32_to_cpu(cck->early_overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", + le32_to_cpu(cck->crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n", + le32_to_cpu(cck->false_alarm_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n", + le32_to_cpu(cck->fina_sync_err_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n", + le32_to_cpu(cck->sfd_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n", + le32_to_cpu(cck->fina_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n", + le32_to_cpu(cck->unresponded_rts)); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_limit_overrun: %u\n", + le32_to_cpu(cck->rxe_frame_limit_overrun)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", + le32_to_cpu(cck->sent_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", + le32_to_cpu(cck->sent_cts_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", + le32_to_cpu(cck->sent_ba_rsp_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", + le32_to_cpu(cck->dsp_self_kill)); + pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", + le32_to_cpu(cck->mh_format_err)); + pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", + le32_to_cpu(cck->re_acq_main_rssi_sum)); + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts: %u\n", + le32_to_cpu(general->bogus_cts)); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack: %u\n", + le32_to_cpu(general->bogus_ack)); + pos += scnprintf(buf + pos, bufsz - pos, "non_bssid_frames: %u\n", + le32_to_cpu(general->non_bssid_frames)); + pos += scnprintf(buf + pos, bufsz - pos, "filtered_frames: %u\n", + le32_to_cpu(general->filtered_frames)); + pos += scnprintf(buf + pos, bufsz - pos, "non_channel_beacons: %u\n", + le32_to_cpu(general->non_channel_beacons)); + pos += scnprintf(buf + pos, bufsz - pos, "channel_beacons: %u\n", + le32_to_cpu(general->channel_beacons)); + pos += scnprintf(buf + pos, bufsz - pos, "num_missed_bcon: %u\n", + le32_to_cpu(general->num_missed_bcon)); + pos += scnprintf(buf + pos, bufsz - pos, + "adc_rx_saturation_time: %u\n", + le32_to_cpu(general->adc_rx_saturation_time)); + pos += scnprintf(buf + pos, bufsz - pos, + "ina_detection_search_time: %u\n", + le32_to_cpu(general->ina_detection_search_time)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_a: %u\n", + le32_to_cpu(general->beacon_silence_rssi_a)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_b: %u\n", + le32_to_cpu(general->beacon_silence_rssi_b)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_c: %u\n", + le32_to_cpu(general->beacon_silence_rssi_c)); + pos += scnprintf(buf + pos, bufsz - pos, + "interference_data_flag: %u\n", + le32_to_cpu(general->interference_data_flag)); + pos += scnprintf(buf + pos, bufsz - pos, "channel_load: %u\n", + le32_to_cpu(general->channel_load)); + pos += scnprintf(buf + pos, bufsz - pos, "dsp_false_alarms: %u\n", + le32_to_cpu(general->dsp_false_alarms)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_a: %u\n", + le32_to_cpu(general->beacon_rssi_a)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_b: %u\n", + le32_to_cpu(general->beacon_rssi_b)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_c: %u\n", + le32_to_cpu(general->beacon_rssi_c)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_a: %u\n", + le32_to_cpu(general->beacon_energy_a)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_b: %u\n", + le32_to_cpu(general->beacon_energy_b)); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_c: %u\n", + le32_to_cpu(general->beacon_energy_c)); + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", + le32_to_cpu(ht->plcp_err)); + pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", + le32_to_cpu(ht->overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", + le32_to_cpu(ht->early_overrun_err)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", + le32_to_cpu(ht->crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", + le32_to_cpu(ht->crc32_err)); + pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", + le32_to_cpu(ht->mh_format_err)); + pos += scnprintf(buf + pos, bufsz - pos, "agg_crc32_good: %u\n", + le32_to_cpu(ht->agg_crc32_good)); + pos += scnprintf(buf + pos, bufsz - pos, "agg_mpdu_cnt: %u\n", + le32_to_cpu(ht->agg_mpdu_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt: %u\n", + le32_to_cpu(ht->agg_cnt)); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = (sizeof(struct statistics_tx) * 24) + 250; + ssize_t ret; + struct statistics_tx *tx; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + tx = &priv->statistics.tx; + pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "preamble: %u\n", + le32_to_cpu(tx->preamble_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "rx_detected_cnt: %u\n", + le32_to_cpu(tx->rx_detected_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_defer_cnt: %u\n", + le32_to_cpu(tx->bt_prio_defer_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_kill_cnt: %u\n", + le32_to_cpu(tx->bt_prio_kill_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "few_bytes_cnt: %u\n", + le32_to_cpu(tx->few_bytes_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout: %u\n", + le32_to_cpu(tx->cts_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "ack_timeout: %u\n", + le32_to_cpu(tx->ack_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, "expected_ack_cnt: %u\n", + le32_to_cpu(tx->expected_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "actual_ack_cnt: %u\n", + le32_to_cpu(tx->actual_ack_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "dump_msdu_cnt: %u\n", + le32_to_cpu(tx->dump_msdu_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, + "burst_abort_next_frame_mismatch_cnt: %u\n", + le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, + "burst_abort_missing_next_frame_cnt: %u\n", + le32_to_cpu(tx->burst_abort_missing_next_frame_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout_collision: %u\n", + le32_to_cpu(tx->cts_timeout_collision)); + pos += scnprintf(buf + pos, bufsz - pos, + "ack_or_ba_timeout_collision: %u\n", + le32_to_cpu(tx->ack_or_ba_timeout_collision)); + pos += scnprintf(buf + pos, bufsz - pos, "agg ba_timeout: %u\n", + le32_to_cpu(tx->agg.ba_timeout)); + pos += scnprintf(buf + pos, bufsz - pos, + "agg ba_reschedule_frames: %u\n", + le32_to_cpu(tx->agg.ba_reschedule_frames)); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_agg_frame_cnt: %u\n", + le32_to_cpu(tx->agg.scd_query_agg_frame_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_no_agg: %u\n", + le32_to_cpu(tx->agg.scd_query_no_agg)); + pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_agg: %u\n", + le32_to_cpu(tx->agg.scd_query_agg)); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_mismatch: %u\n", + le32_to_cpu(tx->agg.scd_query_mismatch)); + pos += scnprintf(buf + pos, bufsz - pos, "agg frame_not_ready: %u\n", + le32_to_cpu(tx->agg.frame_not_ready)); + pos += scnprintf(buf + pos, bufsz - pos, "agg underrun: %u\n", + le32_to_cpu(tx->agg.underrun)); + pos += scnprintf(buf + pos, bufsz - pos, "agg bt_prio_kill: %u\n", + le32_to_cpu(tx->agg.bt_prio_kill)); + pos += scnprintf(buf + pos, bufsz - pos, "agg rx_ba_rsp_cnt: %u\n", + le32_to_cpu(tx->agg.rx_ba_rsp_cnt)); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_general) * 4 + 250; + ssize_t ret; + struct statistics_general *general; + struct statistics_dbg *dbg; + struct statistics_div *div; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + general = &priv->statistics.general; + dbg = &priv->statistics.general.dbg; + div = &priv->statistics.general.div; + pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "temperature: %u\n", + le32_to_cpu(general->temperature)); + pos += scnprintf(buf + pos, bufsz - pos, "temperature_m: %u\n", + le32_to_cpu(general->temperature_m)); + pos += scnprintf(buf + pos, bufsz - pos, "burst_check: %u\n", + le32_to_cpu(dbg->burst_check)); + pos += scnprintf(buf + pos, bufsz - pos, "burst_count: %u\n", + le32_to_cpu(dbg->burst_count)); + pos += scnprintf(buf + pos, bufsz - pos, "sleep_time: %u\n", + le32_to_cpu(general->sleep_time)); + pos += scnprintf(buf + pos, bufsz - pos, "slots_out: %u\n", + le32_to_cpu(general->slots_out)); + pos += scnprintf(buf + pos, bufsz - pos, "slots_idle: %u\n", + le32_to_cpu(general->slots_idle)); + pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp: %u\n", + le32_to_cpu(general->ttl_timestamp)); + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a: %u\n", + le32_to_cpu(div->tx_on_a)); + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b: %u\n", + le32_to_cpu(div->tx_on_b)); + pos += scnprintf(buf + pos, bufsz - pos, "exec_time: %u\n", + le32_to_cpu(div->exec_time)); + pos += scnprintf(buf + pos, bufsz - pos, "probe_time: %u\n", + le32_to_cpu(div->probe_time)); + pos += scnprintf(buf + pos, bufsz - pos, "rx_enable_counter: %u\n", + le32_to_cpu(general->rx_enable_counter)); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + int cnt = 0; + char *buf; + int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100; + ssize_t ret; + struct iwl_sensitivity_data *data; + + data = &priv->sensitivity_data; + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n", + data->auto_corr_ofdm); + pos += scnprintf(buf + pos, bufsz - pos, + "auto_corr_ofdm_mrc:\t\t %u\n", + data->auto_corr_ofdm_mrc); + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n", + data->auto_corr_ofdm_x1); + pos += scnprintf(buf + pos, bufsz - pos, + "auto_corr_ofdm_mrc_x1:\t\t %u\n", + data->auto_corr_ofdm_mrc_x1); + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n", + data->auto_corr_cck); + pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n", + data->auto_corr_cck_mrc); + pos += scnprintf(buf + pos, bufsz - pos, + "last_bad_plcp_cnt_ofdm:\t\t %u\n", + data->last_bad_plcp_cnt_ofdm); + pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n", + data->last_fa_cnt_ofdm); + pos += scnprintf(buf + pos, bufsz - pos, + "last_bad_plcp_cnt_cck:\t\t %u\n", + data->last_bad_plcp_cnt_cck); + pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n", + data->last_fa_cnt_cck); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n", + data->nrg_curr_state); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n", + data->nrg_prev_state); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t"); + for (cnt = 0; cnt < 10; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->nrg_value[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t"); + for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->nrg_silence_rssi[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n", + data->nrg_silence_ref); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n", + data->nrg_energy_idx); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n", + data->nrg_silence_idx); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n", + data->nrg_th_cck); + pos += scnprintf(buf + pos, bufsz - pos, + "nrg_auto_corr_silence_diff:\t %u\n", + data->nrg_auto_corr_silence_diff); + pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n", + data->num_in_cck_no_fa); + pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n", + data->nrg_th_ofdm); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + + +static ssize_t iwl_dbgfs_chain_noise_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + int cnt = 0; + char *buf; + int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100; + ssize_t ret; + struct iwl_chain_noise_data *data; + + data = &priv->chain_noise_data; + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n", + data->active_chains); + pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n", + data->chain_noise_a); + pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n", + data->chain_noise_b); + pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n", + data->chain_noise_c); + pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n", + data->chain_signal_a); + pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n", + data->chain_signal_b); + pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n", + data->chain_signal_c); + pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n", + data->beacon_count); + + pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t"); + for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->disconn_array[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t"); + for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) { + pos += scnprintf(buf + pos, bufsz - pos, " %u", + data->delta_gain_code[cnt]); + } + pos += scnprintf(buf + pos, bufsz - pos, "\n"); + pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n", + data->radio_write); + pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n", + data->state); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_tx_power_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[128]; + int pos = 0; + ssize_t ret; + const size_t bufsz = sizeof(buf); + struct statistics_tx *tx; + + if (!iwl_is_alive(priv)) + pos += scnprintf(buf + pos, bufsz - pos, "N/A\n"); + else { + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, "Error sending statistics request: %zd\n", + ret); + return -EAGAIN; + } + tx = &priv->statistics.tx; + if (tx->tx_power.ant_a || + tx->tx_power.ant_b || + tx->tx_power.ant_c) { + pos += scnprintf(buf + pos, bufsz - pos, + "tx power: (1/2 dB step)\n"); + if ((priv->cfg->valid_tx_ant & ANT_A) && + tx->tx_power.ant_a) + pos += scnprintf(buf + pos, bufsz - pos, + "\tantenna A: 0x%X\n", + tx->tx_power.ant_a); + if ((priv->cfg->valid_tx_ant & ANT_B) && + tx->tx_power.ant_b) + pos += scnprintf(buf + pos, bufsz - pos, + "\tantenna B: 0x%X\n", + tx->tx_power.ant_b); + if ((priv->cfg->valid_tx_ant & ANT_C) && + tx->tx_power.ant_c) + pos += scnprintf(buf + pos, bufsz - pos, + "\tantenna C: 0x%X\n", + tx->tx_power.ant_c); + } else + pos += scnprintf(buf + pos, bufsz - pos, "N/A\n"); + } + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); +DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); +DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); +DEBUGFS_READ_FILE_OPS(rx_queue); +DEBUGFS_READ_FILE_OPS(tx_queue); +DEBUGFS_READ_FILE_OPS(ucode_rx_stats); +DEBUGFS_READ_FILE_OPS(ucode_tx_stats); +DEBUGFS_READ_FILE_OPS(ucode_general_stats); +DEBUGFS_READ_FILE_OPS(sensitivity); +DEBUGFS_READ_FILE_OPS(chain_noise); +DEBUGFS_READ_FILE_OPS(tx_power); /* * Create the debugfs files and directories @@ -738,12 +1652,11 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); + DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv); DEBUGFS_ADD_FILE(nvm, data); DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(log_event, data); DEBUGFS_ADD_FILE(stations, data); - DEBUGFS_ADD_FILE(rx_statistics, data); - DEBUGFS_ADD_FILE(tx_statistics, data); DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_FILE(status, data); DEBUGFS_ADD_FILE(interrupt, data); @@ -751,8 +1664,23 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) #ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_ADD_FILE(led, data); #endif + DEBUGFS_ADD_FILE(sleep_level_override, data); + DEBUGFS_ADD_FILE(current_sleep_command, data); DEBUGFS_ADD_FILE(thermal_throttling, data); DEBUGFS_ADD_FILE(disable_ht40, data); + DEBUGFS_ADD_FILE(rx_statistics, debug); + DEBUGFS_ADD_FILE(tx_statistics, debug); + DEBUGFS_ADD_FILE(traffic_log, debug); + DEBUGFS_ADD_FILE(rx_queue, debug); + DEBUGFS_ADD_FILE(tx_queue, debug); + DEBUGFS_ADD_FILE(tx_power, debug); + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { + DEBUGFS_ADD_FILE(ucode_rx_stats, debug); + DEBUGFS_ADD_FILE(ucode_tx_stats, debug); + DEBUGFS_ADD_FILE(ucode_general_stats, debug); + DEBUGFS_ADD_FILE(sensitivity, debug); + DEBUGFS_ADD_FILE(chain_noise, debug); + } DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -778,9 +1706,9 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) if (!priv->dbgfs) return; + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sleep_level_override); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_current_sleep_command); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); @@ -794,6 +1722,25 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); DEBUGFS_REMOVE(priv->dbgfs->dir_data); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power); + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_rx_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_tx_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_ucode_general_stats); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_sensitivity); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_chain_noise); + } + DEBUGFS_REMOVE(priv->dbgfs->dir_debug); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cab6255210d..028d5059955 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -277,8 +277,8 @@ struct iwl_channel_info { struct iwl4965_channel_tgd_info tgd; struct iwl4965_channel_tgh_info tgh; struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ - struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for - * FAT channel */ + struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for + * HT40 channel */ u8 channel; /* channel number */ u8 flags; /* flags copied from EEPROM */ @@ -291,13 +291,13 @@ struct iwl_channel_info { u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ enum ieee80211_band band; - /* FAT channel info */ - s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ - s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ - s8 fat_min_power; /* always 0 */ - s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */ - u8 fat_flags; /* flags copied from EEPROM */ - u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ + /* HT40 channel info */ + s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + s8 ht40_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ + s8 ht40_min_power; /* always 0 */ + s8 ht40_scan_power; /* (dBm) eeprom, direct scans, any rate */ + u8 ht40_flags; /* flags copied from EEPROM */ + u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ /* Radio/DSP gain settings for each "normal" data Tx rate. * These include, in addition to RF and DSP gain, a few fields for @@ -507,15 +507,9 @@ struct iwl_ht_info { u8 is_ht; u8 supported_chan_width; u8 sm_ps; - u8 is_green_field; - u8 sgf; /* HT_SHORT_GI_* short guard interval */ - u8 max_amsdu_size; - u8 ampdu_factor; - u8 mpdu_density; struct ieee80211_mcs_info mcs; /* BSS related data */ u8 extension_chan_offset; - u8 tx_chan_width; u8 ht_protection; u8 non_GF_STA_present; }; @@ -649,7 +643,7 @@ struct iwl_sensitivity_ranges { * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR * @max_stations: * @bcast_sta_id: - * @fat_channel: is 40MHz width possible in band 2.4 + * @ht40_channel: is 40MHz width possible in band 2.4 * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ) * @sw_crypto: 0 for hw, 1 for sw * @max_xxx_size: for ucode uses @@ -673,7 +667,7 @@ struct iwl_hw_params { u32 max_pkt_size; u8 max_stations; u8 bcast_sta_id; - u8 fat_channel; + u8 ht40_channel; u8 max_beacon_itrvl; /* in 1024 ms */ u32 max_inst_size; u32 max_data_size; @@ -732,9 +726,6 @@ struct iwl_dma_ptr { size_t size; }; -#define HT_SHORT_GI_20MHZ (1 << 0) -#define HT_SHORT_GI_40MHZ (1 << 1) - #define IWL_CHANNEL_WIDTH_20MHZ 0 #define IWL_CHANNEL_WIDTH_40MHZ 1 @@ -823,8 +814,6 @@ struct iwl_calib_result { size_t buf_len; }; -#define UCODE_ALIVE_TIMEOUT (5 * HZ) - enum ucode_type { UCODE_NONE = 0, UCODE_INIT, @@ -877,6 +866,8 @@ struct iwl_chain_noise_data { #define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ #define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ +#define IWL_TRAFFIC_ENTRIES (256) +#define IWL_TRAFFIC_ENTRY_SIZE (64) enum { MEASUREMENT_READY = (1 << 0), @@ -888,6 +879,17 @@ enum iwl_nvm_type { NVM_DEVICE_TYPE_OTP, }; +/* + * Two types of OTP memory access modes + * IWL_OTP_ACCESS_ABSOLUTE - absolute address mode, + * based on physical memory addressing + * IWL_OTP_ACCESS_RELATIVE - relative address mode, + * based on logical memory addressing + */ +enum iwl_access_mode { + IWL_OTP_ACCESS_ABSOLUTE, + IWL_OTP_ACCESS_RELATIVE, +}; /** * enum iwl_pa_type - Power Amplifier type @@ -917,6 +919,48 @@ struct isr_statistics { u32 unhandled; }; +#ifdef CONFIG_IWLWIFI_DEBUGFS +/* management statistics */ +enum iwl_mgmt_stats { + MANAGEMENT_ASSOC_REQ = 0, + MANAGEMENT_ASSOC_RESP, + MANAGEMENT_REASSOC_REQ, + MANAGEMENT_REASSOC_RESP, + MANAGEMENT_PROBE_REQ, + MANAGEMENT_PROBE_RESP, + MANAGEMENT_BEACON, + MANAGEMENT_ATIM, + MANAGEMENT_DISASSOC, + MANAGEMENT_AUTH, + MANAGEMENT_DEAUTH, + MANAGEMENT_ACTION, + MANAGEMENT_MAX, +}; +/* control statistics */ +enum iwl_ctrl_stats { + CONTROL_BACK_REQ = 0, + CONTROL_BACK, + CONTROL_PSPOLL, + CONTROL_RTS, + CONTROL_CTS, + CONTROL_ACK, + CONTROL_CFEND, + CONTROL_CFENDACK, + CONTROL_MAX, +}; + +struct traffic_stats { + u32 mgmt[MANAGEMENT_MAX]; + u32 ctrl[CONTROL_MAX]; + u32 data_cnt; + u64 data_bytes; +}; +#else +struct traffic_stats { + u64 data_bytes; +}; +#endif + #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ struct iwl_priv { @@ -1062,15 +1106,14 @@ struct iwl_priv { int last_rx_noise; /* From beacon statistics */ /* counts mgmt, ctl, and data packets */ - struct traffic_stats { - u32 cnt; - u64 bytes; - } tx_stats[3], rx_stats[3]; + struct traffic_stats tx_stats; + struct traffic_stats rx_stats; /* counts interrupts */ struct isr_statistics isr_stats; struct iwl_power_mgr power_data; + struct iwl_tt_mgmt thermal_throttle; struct iwl_notif_statistics statistics; unsigned long last_statistics_time; @@ -1078,7 +1121,6 @@ struct iwl_priv { /* context information */ u16 rates_mask; - u32 power_mode; u8 bssid[ETH_ALEN]; u16 rts_threshold; u8 mac_addr[ETH_ALEN]; @@ -1128,7 +1170,7 @@ struct iwl_priv { struct iwl_hw_params hw_params; /* INT ICT Table */ - u32 *ict_tbl; + __le32 *ict_tbl; dma_addr_t ict_tbl_dma; dma_addr_t aligned_ict_tbl_dma; int ict_index; @@ -1157,6 +1199,9 @@ struct iwl_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; + struct work_struct tt_work; + struct work_struct ct_enter; + struct work_struct ct_exit; struct tasklet_struct irq_tasklet; @@ -1170,16 +1215,22 @@ struct iwl_priv { /* TX Power */ s8 tx_power_user_lmt; - s8 tx_power_channel_lmt; + s8 tx_power_device_lmt; #ifdef CONFIG_IWLWIFI_DEBUG /* debugging info */ + u32 debug_level; /* per device debugging will override global + iwl_debug_level if set */ u32 framecnt_to_us; atomic_t restrict_refcnt; bool disable_ht40; #ifdef CONFIG_IWLWIFI_DEBUGFS /* debugfs */ + u16 tx_traffic_idx; + u16 rx_traffic_idx; + u8 *tx_traffic; + u8 *rx_traffic; struct iwl_debugfs *dbgfs; #endif /* CONFIG_IWLWIFI_DEBUGFS */ #endif /* CONFIG_IWLWIFI_DEBUG */ @@ -1211,8 +1262,27 @@ static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) #ifdef CONFIG_IWLWIFI_DEBUG const char *iwl_get_tx_fail_reason(u32 status); +/* + * iwl_get_debug_level: Return active debug level for device + * + * Using sysfs it is possible to set per device debug level. This debug + * level will be used if set, otherwise the global debug level which can be + * set via module parameter is used. + */ +static inline u32 iwl_get_debug_level(struct iwl_priv *priv) +{ + if (priv->debug_level) + return priv->debug_level; + else + return iwl_debug_level; +} #else static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; } + +static inline u32 iwl_get_debug_level(struct iwl_priv *priv) +{ + return iwl_debug_level; +} #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 51eed722666..3d2b93a61e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -127,14 +127,86 @@ static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ 145, 149, 153, 157, 161, 165 }; -static const u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */ +static const u8 iwl_eeprom_band_6[] = { /* 2.4 ht40 channel */ 1, 2, 3, 4, 5, 6, 7 }; -static const u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */ +static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 }; +/** + * struct iwl_txpwr_section: eeprom section information + * @offset: indirect address into eeprom image + * @count: number of "struct iwl_eeprom_enhanced_txpwr" in this section + * @band: band type for the section + * @is_common - true: common section, false: channel section + * @is_cck - true: cck section, false: not cck section + * @is_ht_40 - true: all channel in the section are HT40 channel, + * false: legacy or HT 20 MHz + * ignore if it is common section + * @iwl_eeprom_section_channel: channel array in the section, + * ignore if common section + */ +struct iwl_txpwr_section { + u32 offset; + u8 count; + enum ieee80211_band band; + bool is_common; + bool is_cck; + bool is_ht40; + u8 iwl_eeprom_section_channel[EEPROM_MAX_TXPOWER_SECTION_ELEMENTS]; +}; + +/** + * section 1 - 3 are regulatory tx power apply to all channels based on + * modulation: CCK, OFDM + * Band: 2.4GHz, 5.2GHz + * section 4 - 10 are regulatory tx power apply to specified channels + * For example: + * 1L - Channel 1 Legacy + * 1HT - Channel 1 HT + * (1,+1) - Channel 1 HT40 "_above_" + * + * Section 1: all CCK channels + * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40) channels + * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels + * Section 4: 2.4 GHz 20MHz channels: 1L, 1HT, 2L, 2HT, 10L, 10HT, 11L, 11HT + * Section 5: 2.4 GHz 40MHz channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) + * Section 6: 5.2 GHz 20MHz channels: 36L, 64L, 100L, 36HT, 64HT, 100HT + * Section 7: 5.2 GHz 40MHz channels: (36,+1) (60,+1) (100,+1) + * Section 8: 2.4 GHz channel: 13L, 13HT + * Section 9: 2.4 GHz channel: 140L, 140HT + * Section 10: 2.4 GHz 40MHz channels: (132,+1) (44,+1) + * + */ +static const struct iwl_txpwr_section enhinfo[] = { + { EEPROM_LB_CCK_20_COMMON, 1, IEEE80211_BAND_2GHZ, true, true, false }, + { EEPROM_LB_OFDM_COMMON, 3, IEEE80211_BAND_2GHZ, true, false, false }, + { EEPROM_HB_OFDM_COMMON, 3, IEEE80211_BAND_5GHZ, true, false, false }, + { EEPROM_LB_OFDM_20_BAND, 8, IEEE80211_BAND_2GHZ, + false, false, false, + {1, 1, 2, 2, 10, 10, 11, 11 } }, + { EEPROM_LB_OFDM_HT40_BAND, 5, IEEE80211_BAND_2GHZ, + false, false, true, + { 1, 2, 6, 7, 9 } }, + { EEPROM_HB_OFDM_20_BAND, 6, IEEE80211_BAND_5GHZ, + false, false, false, + { 36, 64, 100, 36, 64, 100 } }, + { EEPROM_HB_OFDM_HT40_BAND, 3, IEEE80211_BAND_5GHZ, + false, false, true, + { 36, 60, 100 } }, + { EEPROM_LB_OFDM_20_CHANNEL_13, 2, IEEE80211_BAND_2GHZ, + false, false, false, + { 13, 13 } }, + { EEPROM_HB_OFDM_20_CHANNEL_140, 2, IEEE80211_BAND_5GHZ, + false, false, false, + { 140, 140 } }, + { EEPROM_HB_OFDM_HT40_BAND_1, 2, IEEE80211_BAND_5GHZ, + false, false, true, + { 132, 44 } }, +}; + /****************************************************************************** * * EEPROM related functions @@ -152,6 +224,19 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); +static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) +{ + u32 otpgp; + + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (mode == IWL_OTP_ACCESS_ABSOLUTE) + iwl_clear_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_OTP_ACCESS_MODE); + else + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_OTP_ACCESS_MODE); +} + static int iwlcore_get_nvm_type(struct iwl_priv *priv) { u32 otpgp; @@ -252,6 +337,124 @@ static int iwl_init_otp_access(struct iwl_priv *priv) return ret; } +static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) +{ + int ret = 0; + u32 r; + u32 otpgp; + + _iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { + IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + return ret; + } + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + /* check for ECC errors: */ + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { + /* stop in this case */ + /* set the uncorrectable OTP ECC bit for acknowledgement */ + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); + IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n"); + return -EINVAL; + } + if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { + /* continue in this case */ + /* set the correctable OTP ECC bit for acknowledgement */ + iwl_set_bit(priv, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); + IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); + } + *eeprom_data = le16_to_cpu((__force __le16)(r >> 16)); + return 0; +} + +/* + * iwl_is_otp_empty: check for empty OTP + */ +static bool iwl_is_otp_empty(struct iwl_priv *priv) +{ + u16 next_link_addr = 0, link_value; + bool is_empty = false; + + /* locate the beginning of OTP link list */ + if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) { + if (!link_value) { + IWL_ERR(priv, "OTP is empty\n"); + is_empty = true; + } + } else { + IWL_ERR(priv, "Unable to read first block of OTP list.\n"); + is_empty = true; + } + + return is_empty; +} + + +/* + * iwl_find_otp_image: find EEPROM image in OTP + * finding the OTP block that contains the EEPROM image. + * the last valid block on the link list (the block _before_ the last block) + * is the block we should read and used to configure the device. + * If all the available OTP blocks are full, the last block will be the block + * we should read and used to configure the device. + * only perform this operation if shadow RAM is disabled + */ +static int iwl_find_otp_image(struct iwl_priv *priv, + u16 *validblockaddr) +{ + u16 next_link_addr = 0, link_value = 0, valid_addr; + int ret = 0; + int usedblocks = 0; + + /* set addressing mode to absolute to traverse the link list */ + iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE); + + /* checking for empty OTP or error */ + if (iwl_is_otp_empty(priv)) + return -EINVAL; + + /* + * start traverse link list + * until reach the max number of OTP blocks + * different devices have different number of OTP blocks + */ + do { + /* save current valid block address + * check for more block on the link list + */ + valid_addr = next_link_addr; + next_link_addr = link_value; + IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n", + usedblocks, next_link_addr); + if (iwl_read_otp_word(priv, next_link_addr, &link_value)) + return -EINVAL; + if (!link_value) { + /* + * reach the end of link list, + * set address point to the starting address + * of the image + */ + goto done; + } + /* more in the link list, continue */ + usedblocks++; + } while (usedblocks < priv->cfg->max_ll_items); + /* OTP full, use last block */ + IWL_DEBUG_INFO(priv, "OTP is full, use last block\n"); +done: + *validblockaddr = valid_addr; + /* skip first 2 bytes (link list pointer) */ + *validblockaddr += 2; + return ret; +} + /** * iwl_eeprom_init - read EEPROM contents * @@ -266,15 +469,14 @@ int iwl_eeprom_init(struct iwl_priv *priv) int sz; int ret; u16 addr; - u32 otpgp; + u16 validblockaddr = 0; + u16 cache_addr = 0; priv->nvm_device_type = iwlcore_get_nvm_type(priv); if (priv->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ - if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) - priv->cfg->eeprom_size = - OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL; + IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size); sz = priv->cfg->eeprom_size; priv->eeprom = kzalloc(sz, GFP_KERNEL); if (!priv->eeprom) { @@ -302,46 +504,31 @@ int iwl_eeprom_init(struct iwl_priv *priv) if (ret) { IWL_ERR(priv, "Failed to initialize OTP access.\n"); ret = -ENOENT; - goto err; + goto done; } _iwl_write32(priv, CSR_EEPROM_GP, iwl_read32(priv, CSR_EEPROM_GP) & ~CSR_EEPROM_GP_IF_OWNER_MSK); - /* clear */ - _iwl_write32(priv, CSR_OTP_GP_REG, - iwl_read32(priv, CSR_OTP_GP_REG) | + + iwl_set_bit(priv, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); - - for (addr = 0; addr < sz; addr += sizeof(u16)) { - u32 r; - - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - - ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); - if (ret < 0) { - IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + /* traversing the linked list if no shadow ram supported */ + if (!priv->cfg->shadow_ram_support) { + if (iwl_find_otp_image(priv, &validblockaddr)) { + ret = -ENOENT; goto done; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); - /* check for ECC errors: */ - otpgp = iwl_read32(priv, CSR_OTP_GP_REG); - if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { - /* stop in this case */ - IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n"); + } + for (addr = validblockaddr; addr < validblockaddr + sz; + addr += sizeof(u16)) { + u16 eeprom_data; + + ret = iwl_read_otp_word(priv, addr, &eeprom_data); + if (ret) goto done; - } - if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { - /* continue in this case */ - _iwl_write32(priv, CSR_OTP_GP_REG, - iwl_read32(priv, CSR_OTP_GP_REG) | - CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); - IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); - } - e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); + e[cache_addr / 2] = eeprom_data; + cache_addr += sizeof(u16); } } else { /* eeprom is an array of 16bit values */ @@ -462,13 +649,13 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_5; break; - case 6: /* 2.4GHz FAT channels */ + case 6: /* 2.4GHz ht40 channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); *eeprom_ch_info = (struct iwl_eeprom_channel *) iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_6; break; - case 7: /* 5 GHz FAT channels */ + case 7: /* 5 GHz ht40 channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); *eeprom_ch_info = (struct iwl_eeprom_channel *) iwl_eeprom_query_addr(priv, offset); @@ -484,14 +671,14 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, ? # x " " : "") /** - * iwl_set_fat_chan_info - Copy fat channel info into driver's priv. + * iwl_mod_ht40_chan_info - Copy ht40 channel info into driver's priv. * * Does not set up a command, or touch hardware. */ -static int iwl_set_fat_chan_info(struct iwl_priv *priv, +static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, const struct iwl_eeprom_channel *eeprom_ch, - u8 fat_extension_channel) + u8 clear_ht40_extension_channel) { struct iwl_channel_info *ch_info; @@ -501,7 +688,7 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv, if (!is_channel_valid(ch_info)) return -1; - IWL_DEBUG_INFO(priv, "FAT Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):" + IWL_DEBUG_INFO(priv, "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):" " Ad-Hoc %ssupported\n", ch_info->channel, is_channel_a_band(ch_info) ? @@ -517,17 +704,189 @@ static int iwl_set_fat_chan_info(struct iwl_priv *priv, && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); - ch_info->fat_eeprom = *eeprom_ch; - ch_info->fat_max_power_avg = eeprom_ch->max_power_avg; - ch_info->fat_curr_txpow = eeprom_ch->max_power_avg; - ch_info->fat_min_power = 0; - ch_info->fat_scan_power = eeprom_ch->max_power_avg; - ch_info->fat_flags = eeprom_ch->flags; - ch_info->fat_extension_channel = fat_extension_channel; + ch_info->ht40_eeprom = *eeprom_ch; + ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg; + ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg; + ch_info->ht40_min_power = 0; + ch_info->ht40_scan_power = eeprom_ch->max_power_avg; + ch_info->ht40_flags = eeprom_ch->flags; + ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; return 0; } +/** + * iwl_get_max_txpower_avg - get the highest tx power from all chains. + * find the highest tx power from all chains for the channel + */ +static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element) +{ + s8 max_txpower_avg = 0; /* (dBm) */ + + IWL_DEBUG_INFO(priv, "%d - " + "chain_a: %d dB chain_b: %d dB " + "chain_c: %d dB mimo2: %d dB mimo3: %d dB\n", + element, + enhanced_txpower[element].chain_a_max >> 1, + enhanced_txpower[element].chain_b_max >> 1, + enhanced_txpower[element].chain_c_max >> 1, + enhanced_txpower[element].mimo2_max >> 1, + enhanced_txpower[element].mimo3_max >> 1); + /* Take the highest tx power from any valid chains */ + if ((priv->cfg->valid_tx_ant & ANT_A) && + (enhanced_txpower[element].chain_a_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_a_max; + if ((priv->cfg->valid_tx_ant & ANT_B) && + (enhanced_txpower[element].chain_b_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_b_max; + if ((priv->cfg->valid_tx_ant & ANT_C) && + (enhanced_txpower[element].chain_c_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_c_max; + if (((priv->cfg->valid_tx_ant == ANT_AB) | + (priv->cfg->valid_tx_ant == ANT_BC) | + (priv->cfg->valid_tx_ant == ANT_AC)) && + (enhanced_txpower[element].mimo2_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].mimo2_max; + if ((priv->cfg->valid_tx_ant == ANT_ABC) && + (enhanced_txpower[element].mimo3_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].mimo3_max; + + /* max. tx power in EEPROM is in 1/2 dBm format + * convert from 1/2 dBm to dBm + */ + return max_txpower_avg >> 1; +} + +/** + * iwl_update_common_txpower: update channel tx power + * update tx power per band based on EEPROM enhanced tx power info. + */ +static s8 iwl_update_common_txpower(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int section, int element) +{ + struct iwl_channel_info *ch_info; + int ch; + bool is_ht40 = false; + s8 max_txpower_avg; /* (dBm) */ + + /* it is common section, contain all type (Legacy, HT and HT40) + * based on the element in the section to determine + * is it HT 40 or not + */ + if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) + is_ht40 = true; + max_txpower_avg = + iwl_get_max_txpower_avg(priv, enhanced_txpower, element); + ch_info = priv->channel_info; + + for (ch = 0; ch < priv->channel_count; ch++) { + /* find matching band and update tx power if needed */ + if ((ch_info->band == enhinfo[section].band) && + (ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) { + /* Update regulatory-based run-time data */ + ch_info->max_power_avg = ch_info->curr_txpow = + max_txpower_avg; + ch_info->scan_power = max_txpower_avg; + } + if ((ch_info->band == enhinfo[section].band) && is_ht40 && + ch_info->ht40_max_power_avg && + (ch_info->ht40_max_power_avg < max_txpower_avg)) { + /* Update regulatory-based run-time data */ + ch_info->ht40_max_power_avg = max_txpower_avg; + ch_info->ht40_curr_txpow = max_txpower_avg; + ch_info->ht40_scan_power = max_txpower_avg; + } + ch_info++; + } + return max_txpower_avg; +} + +/** + * iwl_update_channel_txpower: update channel tx power + * update channel tx power based on EEPROM enhanced tx power info. + */ +static s8 iwl_update_channel_txpower(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int section, int element) +{ + struct iwl_channel_info *ch_info; + int ch; + u8 channel; + s8 max_txpower_avg; /* (dBm) */ + + channel = enhinfo[section].iwl_eeprom_section_channel[element]; + max_txpower_avg = + iwl_get_max_txpower_avg(priv, enhanced_txpower, element); + + ch_info = priv->channel_info; + for (ch = 0; ch < priv->channel_count; ch++) { + /* find matching channel and update tx power if needed */ + if (ch_info->channel == channel) { + if ((ch_info->max_power_avg < max_txpower_avg) && + (!enhinfo[section].is_ht40)) { + /* Update regulatory-based run-time data */ + ch_info->max_power_avg = max_txpower_avg; + ch_info->curr_txpow = max_txpower_avg; + ch_info->scan_power = max_txpower_avg; + } + if ((enhinfo[section].is_ht40) && + (ch_info->ht40_max_power_avg) && + (ch_info->ht40_max_power_avg < max_txpower_avg)) { + /* Update regulatory-based run-time data */ + ch_info->ht40_max_power_avg = max_txpower_avg; + ch_info->ht40_curr_txpow = max_txpower_avg; + ch_info->ht40_scan_power = max_txpower_avg; + } + break; + } + ch_info++; + } + return max_txpower_avg; +} + +/** + * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info + */ +void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) +{ + int eeprom_section_count = 0; + int section, element; + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; + u32 offset; + s8 max_txpower_avg; /* (dBm) */ + + /* Loop through all the sections + * adjust bands and channel's max tx power + * Set the tx_power_user_lmt to the highest power + * supported by any channels and chains + */ + for (section = 0; section < ARRAY_SIZE(enhinfo); section++) { + eeprom_section_count = enhinfo[section].count; + offset = enhinfo[section].offset; + enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *) + iwl_eeprom_query_addr(priv, offset); + + for (element = 0; element < eeprom_section_count; element++) { + if (enhinfo[section].is_common) + max_txpower_avg = + iwl_update_common_txpower(priv, + enhanced_txpower, section, element); + else + max_txpower_avg = + iwl_update_channel_txpower(priv, + enhanced_txpower, section, element); + + /* Update the tx_power_user_lmt to the highest power + * supported by any channel */ + if (max_txpower_avg > priv->tx_power_user_lmt) + priv->tx_power_user_lmt = max_txpower_avg; + } + } +} +EXPORT_SYMBOL(iwlcore_eeprom_enhanced_txpower); + #define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ ? # x " " : "") @@ -589,11 +948,10 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Copy the run-time flags so they are there even on * invalid channels */ ch_info->flags = eeprom_ch_info[ch].flags; - /* First write that fat is not enabled, and then enable + /* First write that ht40 is not enabled, and then enable * one by one */ - ch_info->fat_extension_channel = - (IEEE80211_CHAN_NO_HT40PLUS | - IEEE80211_CHAN_NO_HT40MINUS); + ch_info->ht40_extension_channel = + IEEE80211_CHAN_NO_HT40; if (!(is_channel_valid(ch_info))) { IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - " @@ -642,17 +1000,16 @@ int iwl_init_channel_map(struct iwl_priv *priv) } } - /* Check if we do have FAT channels */ + /* Check if we do have HT40 channels */ if (priv->cfg->ops->lib->eeprom_ops.regulatory_bands[5] == - EEPROM_REGULATORY_BAND_NO_FAT && + EEPROM_REGULATORY_BAND_NO_HT40 && priv->cfg->ops->lib->eeprom_ops.regulatory_bands[6] == - EEPROM_REGULATORY_BAND_NO_FAT) + EEPROM_REGULATORY_BAND_NO_HT40) return 0; - /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */ + /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */ for (band = 6; band <= 7; band++) { enum ieee80211_band ieeeband; - u8 fat_extension_chan; iwl_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); @@ -663,31 +1020,28 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { - - if ((band == 6) && - ((eeprom_ch_index[ch] == 5) || - (eeprom_ch_index[ch] == 6) || - (eeprom_ch_index[ch] == 7))) - /* both are allowed: above and below */ - fat_extension_chan = 0; - else - fat_extension_chan = - IEEE80211_CHAN_NO_HT40MINUS; - /* Set up driver's info for lower half */ - iwl_set_fat_chan_info(priv, ieeeband, + iwl_mod_ht40_chan_info(priv, ieeeband, eeprom_ch_index[ch], - &(eeprom_ch_info[ch]), - fat_extension_chan); + &eeprom_ch_info[ch], + IEEE80211_CHAN_NO_HT40PLUS); /* Set up driver's info for upper half */ - iwl_set_fat_chan_info(priv, ieeeband, - (eeprom_ch_index[ch] + 4), - &(eeprom_ch_info[ch]), - IEEE80211_CHAN_NO_HT40PLUS); + iwl_mod_ht40_chan_info(priv, ieeeband, + eeprom_ch_index[ch] + 4, + &eeprom_ch_info[ch], + IEEE80211_CHAN_NO_HT40MINUS); } } + /* for newer device (6000 series and up) + * EEPROM contain enhanced tx power information + * driver need to process addition information + * to determine the max channel tx power limits + */ + if (priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower) + priv->cfg->ops->lib->eeprom_ops.update_enhanced_txpower(priv); + return 0; } EXPORT_SYMBOL(iwl_init_channel_map); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 195b4ef12c2..6b68db7b1b8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -88,10 +88,10 @@ struct iwl_priv; * requirement for establishing a new network for legal operation on channels * requiring RADAR detection or restricting ACTIVE scanning. * - * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels. - * It only indicates that 20 MHz channel use is supported; FAT channel + * NOTE: "WIDE" flag does not indicate anything about "HT40" 40 MHz channels. + * It only indicates that 20 MHz channel use is supported; HT40 channel * usage is indicated by a separate set of regulatory flags for each - * FAT channel pair. + * HT40 channel pair. * * NOTE: Using a channel inappropriately will result in a uCode error! */ @@ -112,12 +112,36 @@ enum { #define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) /* *regulatory* channel data format in eeprom, one for each channel. - * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */ + * There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */ struct iwl_eeprom_channel { u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ } __attribute__ ((packed)); +/** + * iwl_eeprom_enhanced_txpwr structure + * This structure presents the enhanced regulatory tx power limit layout + * in eeprom image + * Enhanced regulatory tx power portion of eeprom image can be broken down + * into individual structures; each one is 8 bytes in size and contain the + * following information + * @chain_a_max_pwr: chain a max power in 1/2 dBm + * @chain_b_max_pwr: chain b max power in 1/2 dBm + * @chain_c_max_pwr: chain c max power in 1/2 dBm + * @mimo2_max_pwr: mimo2 max power in 1/2 dBm + * @mimo3_max_pwr: mimo3 max power in 1/2 dBm + * + */ +struct iwl_eeprom_enhanced_txpwr { + u16 reserved; + s8 chain_a_max; + s8 chain_b_max; + s8 chain_c_max; + s8 reserved1; + s8 mimo2_max; + s8 mimo3_max; +} __attribute__ ((packed)); + /* 3945 Specific */ #define EEPROM_3945_EEPROM_VERSION (0x2f) @@ -170,18 +194,77 @@ struct iwl_eeprom_channel { | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ #define EEPROM_5000_REG_BAND_5_CHANNELS ((0x74)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 12 bytes */ -#define EEPROM_5000_REG_BAND_24_FAT_CHANNELS ((0x82)\ +#define EEPROM_5000_REG_BAND_24_HT40_CHANNELS ((0x82)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */ -#define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\ +#define EEPROM_5000_REG_BAND_52_HT40_CHANNELS ((0x92)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ +/* 6000 and up regulatory tx power - indirect access */ +/* max. elements per section */ +#define EEPROM_MAX_TXPOWER_SECTION_ELEMENTS (8) +#define EEPROM_TXPOWER_COMMON_HT40_INDEX (2) + +/** + * Partition the enhanced tx power portion of eeprom image into + * 10 sections based on band, modulation, frequency and channel + * + * Section 1: all CCK channels + * Section 2: all 2.4 GHz OFDM (Legacy, HT and HT40 ) channels + * Section 3: all 5.2 GHz OFDM (Legacy, HT and HT40) channels + * Section 4: 2.4 GHz 20MHz channels: 1, 2, 10, 11. Both Legacy and HT + * Section 5: 2.4 GHz 40MHz channels: 1, 2, 6, 7, 9, (_above_) + * Section 6: 5.2 GHz 20MHz channels: 36, 64, 100, both Legacy and HT + * Section 7: 5.2 GHz 40MHz channels: 36, 60, 100 (_above_) + * Section 8: 2.4 GHz channel 13, Both Legacy and HT + * Section 9: 2.4 GHz channel 140, Both Legacy and HT + * Section 10: 2.4 GHz 40MHz channels: 132, 44 (_above_) + */ +/* 2.4 GHz band: CCK */ +#define EEPROM_LB_CCK_20_COMMON ((0xAA)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 8 bytes */ +/* 2.4 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */ +#define EEPROM_LB_OFDM_COMMON ((0xB2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */ +/* 5.2 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */ +#define EEPROM_HB_OFDM_COMMON ((0xCA)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */ +/* 2.4GHz band channels: + * 1Legacy, 1HT, 2Legacy, 2HT, 10Legacy, 10HT, 11Legacy, 11HT */ +#define EEPROM_LB_OFDM_20_BAND ((0xE2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 64 bytes */ +/* 2.4 GHz band HT40 channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) */ +#define EEPROM_LB_OFDM_HT40_BAND ((0x122)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 40 bytes */ +/* 5.2GHz band channels: 36Legacy, 36HT, 64Legacy, 64HT, 100Legacy, 100HT */ +#define EEPROM_HB_OFDM_20_BAND ((0x14A)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 48 bytes */ +/* 5.2 GHz band HT40 channels: (36,+1) (60,+1) (100,+1) */ +#define EEPROM_HB_OFDM_HT40_BAND ((0x17A)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */ +/* 2.4 GHz band, channnel 13: Legacy, HT */ +#define EEPROM_LB_OFDM_20_CHANNEL_13 ((0x192)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */ +/* 5.2 GHz band, channnel 140: Legacy, HT */ +#define EEPROM_HB_OFDM_20_CHANNEL_140 ((0x1A2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */ +/* 5.2 GHz band, HT40 channnels (132,+1) (44,+1) */ +#define EEPROM_HB_OFDM_HT40_BAND_1 ((0x1B2)\ + | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */ + + /* 5050 Specific */ #define EEPROM_5050_TX_POWER_VERSION (4) #define EEPROM_5050_EEPROM_VERSION (0x21E) /* OTP */ -#define OTP_LOWER_BLOCKS_TOTAL (3) -#define OTP_BLOCK_SIZE (0x400) +/* lower blocks contain EEPROM image and calibration data */ +#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ +/* high blocks contain PAPD data */ +#define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16)) /* 6 KB */ +#define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16)) /* 1024 bytes */ +#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */ +#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */ +#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */ /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; @@ -313,7 +396,7 @@ struct iwl_eeprom_calib_info { * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory * txpower (MSB). * - * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) + * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) * channels (only for 4965, not supported by 3945) appear later in the EEPROM. * * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 @@ -352,29 +435,29 @@ struct iwl_eeprom_calib_info { #define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ /* - * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) + * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) * * The channel listed is the center of the lower 20 MHz half of the channel. * The overall center frequency is actually 2 channels (10 MHz) above that, - * and the upper half of each FAT channel is centered 4 channels (20 MHz) away - * from the lower half; e.g. the upper half of FAT channel 1 is channel 5, - * and the overall FAT channel width centers on channel 3. + * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away + * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5, + * and the overall HT40 channel width centers on channel 3. * * NOTE: The RXON command uses 20 MHz channel numbers to specify the * control channel to which to tune. RXON also specifies whether the - * control channel is the upper or lower half of a FAT channel. + * control channel is the upper or lower half of a HT40 channel. * - * NOTE: 4965 does not support FAT channels on 2.4 GHz. + * NOTE: 4965 does not support HT40 channels on 2.4 GHz. */ -#define EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ +#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */ /* - * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64), + * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64), * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) */ -#define EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ +#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */ -#define EEPROM_REGULATORY_BAND_NO_FAT (0) +#define EEPROM_REGULATORY_BAND_NO_HT40 (0) struct iwl_eeprom_ops { const u32 regulatory_bands[7]; @@ -383,6 +466,7 @@ struct iwl_eeprom_ops { void (*release_semaphore) (struct iwl_priv *priv); u16 (*calib_version) (struct iwl_priv *priv); const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); + void (*update_enhanced_txpower) (struct iwl_priv *priv); }; @@ -397,7 +481,7 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); - +void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv); int iwl_init_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv); const struct iwl_channel_info *iwl_get_channel_info( diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index b82ad15d518..532c8d6cd8d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -36,8 +36,6 @@ #include "iwl-core.h" -#define IWL_CMD(x) case x: return #x - const char *get_cmd_string(u8 cmd) { switch (cmd) { diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 3d61cb43151..f420c99e724 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -272,7 +272,8 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) /* count both tx and rx traffic to be able to * handle traffic in either direction */ - u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes; + u64 current_tpt = priv->tx_stats.data_bytes + + priv->rx_stats.data_bytes; s64 tpt = current_tpt - priv->led_tpt; if (tpt < 0) /* wraparound */ diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 00937b3ee8e..4ec6a8307cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -42,20 +42,35 @@ #include "iwl-power.h" /* - * Setting power level allow the card to go to sleep when not busy. + * Setting power level allows the card to go to sleep when not busy. * - * The power level is set to INDEX_1 (the least deep state) by - * default, and will, in the future, be the deepest state unless - * otherwise required by pm_qos network latency requirements. - * - * Using INDEX_1 without pm_qos is ok because mac80211 will disable - * PS when even checking every beacon for the TIM bit would exceed - * the required latency. + * We calculate a sleep command based on the required latency, which + * we get from mac80211. In order to handle thermal throttling, we can + * also use pre-defined power levels. */ -#define IWL_POWER_RANGE_0_MAX (2) -#define IWL_POWER_RANGE_1_MAX (10) +/* + * For now, keep using power level 1 instead of automatically + * adjusting ... + */ +bool no_sleep_autoadjust = true; +module_param(no_sleep_autoadjust, bool, S_IRUGO); +MODULE_PARM_DESC(no_sleep_autoadjust, + "don't automatically adjust sleep level " + "according to maximum network latency"); +/* + * This defines the old power levels. They are still used by default + * (level 1) and for thermal throttle (levels 3 through 5) + */ + +struct iwl_power_vec_entry { + struct iwl_powertable_cmd cmd; + u8 no_dtim; +}; + +#define IWL_DTIM_RANGE_0_MAX 2 +#define IWL_DTIM_RANGE_1_MAX 10 #define NOSLP cpu_to_le16(0), 0, 0 #define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 @@ -67,9 +82,8 @@ cpu_to_le32(X3), \ cpu_to_le32(X4)} /* default power management (not Tx power) table values */ -/* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */ +/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { - {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, @@ -78,9 +92,8 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { }; -/* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */ +/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { - {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, @@ -88,9 +101,8 @@ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} }; -/* for DTIM period > IWL_POWER_RANGE_1_MAX */ +/* for DTIM period > IWL_DTIM_RANGE_1_MAX */ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { - {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, @@ -98,6 +110,56 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} }; +static void iwl_static_sleep_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd, + enum iwl_power_level lvl, int period) +{ + const struct iwl_power_vec_entry *table; + int max_sleep, i; + bool skip; + + table = range_2; + if (period < IWL_DTIM_RANGE_1_MAX) + table = range_1; + if (period < IWL_DTIM_RANGE_0_MAX) + table = range_0; + + BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); + + *cmd = table[lvl].cmd; + + if (period == 0) { + skip = false; + period = 1; + } else { + skip = !!table[lvl].no_dtim; + } + + if (skip) { + __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; + max_sleep = le32_to_cpu(slp_itrvl); + if (max_sleep == 0xFF) + max_sleep = period * (skip + 1); + else if (max_sleep > period) + max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; + cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; + } else { + max_sleep = period; + cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; + } + + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) + if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) + cmd->sleep_interval[i] = cpu_to_le32(max_sleep); + + if (priv->power_data.pci_pm) + cmd->flags |= IWL_POWER_PCI_PM_MSK; + else + cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + + IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1); +} + /* default Thermal Throttling transaction table * Current state | Throttling Down | Throttling Up *============================================================================= @@ -132,104 +194,70 @@ static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = { /* Advance Thermal Throttling default restriction table */ static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { - {IWL_TX_MULTI, true, IWL_RX_MULTI}, - {IWL_TX_SINGLE, true, IWL_RX_MULTI}, - {IWL_TX_SINGLE, false, IWL_RX_SINGLE}, - {IWL_TX_NONE, false, IWL_RX_NONE} + {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true }, + {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true }, + {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false }, + {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false } }; -/* set card power command */ -static int iwl_set_power(struct iwl_priv *priv, void *cmd) -{ - return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, - sizeof(struct iwl_powertable_cmd), cmd); -} -/* initialize to default */ -static void iwl_power_init_handle(struct iwl_priv *priv) +static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd) { - struct iwl_power_mgr *pow_data; - int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM; - struct iwl_powertable_cmd *cmd; - int i; - u16 lctl; - - IWL_DEBUG_POWER(priv, "Initialize power \n"); - - pow_data = &priv->power_data; - - memset(pow_data, 0, sizeof(*pow_data)); + memset(cmd, 0, sizeof(*cmd)); - memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); - memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); - memcpy(&pow_data->pwr_range_2[0], &range_2[0], size); + if (priv->power_data.pci_pm) + cmd->flags |= IWL_POWER_PCI_PM_MSK; - lctl = iwl_pcie_link_ctl(priv); - - IWL_DEBUG_POWER(priv, "adjust power command flags\n"); - - for (i = 0; i < IWL_POWER_NUM; i++) { - cmd = &pow_data->pwr_range_0[i].cmd; - - if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN) - cmd->flags &= ~IWL_POWER_PCI_PM_MSK; - else - cmd->flags |= IWL_POWER_PCI_PM_MSK; - } + IWL_DEBUG_POWER(priv, "Sleep command for CAM\n"); } -/* adjust power command according to DTIM period and power level*/ -static int iwl_update_power_cmd(struct iwl_priv *priv, - struct iwl_powertable_cmd *cmd, u16 mode) +static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd, + int dynps_ms, int wakeup_period) { - struct iwl_power_vec_entry *range; - struct iwl_power_mgr *pow_data; + /* + * These are the original power level 3 sleep successions. The + * device may behave better with such succession and was also + * only tested with that. Just like the original sleep commands, + * also adjust the succession here to the wakeup_period below. + * The ranges are the same as for the sleep commands, 0-2, 3-9 + * and >10, which is selected based on the DTIM interval for + * the sleep index but here we use the wakeup period since that + * is what we need to do for the latency requirements. + */ + static const u8 slp_succ_r0[IWL_POWER_VEC_SIZE] = { 2, 2, 2, 2, 2 }; + static const u8 slp_succ_r1[IWL_POWER_VEC_SIZE] = { 2, 4, 6, 7, 9 }; + static const u8 slp_succ_r2[IWL_POWER_VEC_SIZE] = { 2, 7, 9, 9, 0xFF }; + const u8 *slp_succ = slp_succ_r0; int i; - u32 max_sleep = 0; - u8 period; - bool skip; - if (mode > IWL_POWER_INDEX_5) { - IWL_DEBUG_POWER(priv, "Error invalid power mode \n"); - return -EINVAL; - } + if (wakeup_period > IWL_DTIM_RANGE_0_MAX) + slp_succ = slp_succ_r1; + if (wakeup_period > IWL_DTIM_RANGE_1_MAX) + slp_succ = slp_succ_r2; - pow_data = &priv->power_data; + memset(cmd, 0, sizeof(*cmd)); - if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX) - range = &pow_data->pwr_range_0[0]; - else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX) - range = &pow_data->pwr_range_1[0]; - else - range = &pow_data->pwr_range_2[0]; + cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK | + IWL_POWER_FAST_PD; /* no use seeing frames for others */ - period = pow_data->dtim_period; - memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); + if (priv->power_data.pci_pm) + cmd->flags |= IWL_POWER_PCI_PM_MSK; - if (period == 0) { - period = 1; - skip = false; - } else { - skip = !!range[mode].no_dtim; - } - - if (skip) { - __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; - max_sleep = le32_to_cpu(slp_itrvl); - if (max_sleep == 0xFF) - max_sleep = period * (skip + 1); - else if (max_sleep > period) - max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; - cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; - } else { - max_sleep = period; - cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; - } + cmd->rx_data_timeout = cpu_to_le32(1000 * dynps_ms); + cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms); for (i = 0; i < IWL_POWER_VEC_SIZE; i++) - if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) - cmd->sleep_interval[i] = cpu_to_le32(max_sleep); + cmd->sleep_interval[i] = + cpu_to_le32(min_t(int, slp_succ[i], wakeup_period)); + + IWL_DEBUG_POWER(priv, "Automatic sleep command\n"); +} +static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd) +{ + IWL_DEBUG_POWER(priv, "Sending power/sleep command\n"); IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags); IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); @@ -240,113 +268,107 @@ static int iwl_update_power_cmd(struct iwl_priv *priv, le32_to_cpu(cmd->sleep_interval[3]), le32_to_cpu(cmd->sleep_interval[4])); - return 0; + return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, + sizeof(struct iwl_powertable_cmd), cmd); } -/* - * compute the final power mode index - */ int iwl_power_update_mode(struct iwl_priv *priv, bool force) { - struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; - struct iwl_tt_mgmt *tt = &priv->power_data.tt; - u16 uninitialized_var(final_mode); + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; + bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) && + (priv->hw->conf.flags & IEEE80211_CONF_PS); bool update_chains; + struct iwl_powertable_cmd cmd; + int dtimper; /* Don't update the RX chain when chain noise calibration is running */ update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; - final_mode = priv->power_data.user_power_setting; - - if (setting->power_disabled) - final_mode = IWL_POWER_MODE_CAM; + if (priv->vif) + dtimper = priv->vif->bss_conf.dtim_period; + else + dtimper = 1; + + /* TT power setting overwrites everything */ + if (tt->state >= IWL_TI_1) + iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper); + else if (!enabled) + iwl_power_sleep_cam_cmd(priv, &cmd); + else if (priv->power_data.debug_sleep_level_override >= 0) + iwl_static_sleep_cmd(priv, &cmd, + priv->power_data.debug_sleep_level_override, + dtimper); + else if (no_sleep_autoadjust) + iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper); + else + iwl_power_fill_sleep_cmd(priv, &cmd, + priv->hw->conf.dynamic_ps_timeout, + priv->hw->conf.max_sleep_period); - if (tt->state >= IWL_TI_1) { - /* TT power setting overwrite user & system power setting */ - final_mode = tt->tt_power_mode; - } if (iwl_is_ready_rf(priv) && - ((setting->power_mode != final_mode) || force)) { - struct iwl_powertable_cmd cmd; - - if (final_mode != IWL_POWER_MODE_CAM) + (memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) { + if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) set_bit(STATUS_POWER_PMI, &priv->status); - iwl_update_power_cmd(priv, &cmd, final_mode); - cmd.keep_alive_beacons = 0; - - if (final_mode == IWL_POWER_INDEX_5) - cmd.flags |= IWL_POWER_FAST_PD; - ret = iwl_set_power(priv, &cmd); - - if (final_mode == IWL_POWER_MODE_CAM) - clear_bit(STATUS_POWER_PMI, &priv->status); - - if (priv->cfg->ops->lib->update_chain_flags && update_chains) - priv->cfg->ops->lib->update_chain_flags(priv); - else - IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise " + if (!ret) { + if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) + clear_bit(STATUS_POWER_PMI, &priv->status); + + if (priv->cfg->ops->lib->update_chain_flags && + update_chains) + priv->cfg->ops->lib->update_chain_flags(priv); + else if (priv->cfg->ops->lib->update_chain_flags) + IWL_DEBUG_POWER(priv, + "Cannot update the power, chain noise " "calibration running: %d\n", priv->chain_noise_data.state); - if (!ret) - setting->power_mode = final_mode; + memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)); + } else + IWL_ERR(priv, "set power fail, ret = %d", ret); } return ret; } EXPORT_SYMBOL(iwl_power_update_mode); -/* set user_power_setting */ -int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) -{ - if (mode >= IWL_POWER_NUM) - return -EINVAL; - - priv->power_data.user_power_setting = mode; - - return iwl_power_update_mode(priv, 0); -} -EXPORT_SYMBOL(iwl_power_set_user_mode); - bool iwl_ht_enabled(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) return true; restriction = tt->restriction + tt->state; return restriction->is_ht; } EXPORT_SYMBOL(iwl_ht_enabled); -u8 iwl_tx_ant_restriction(struct iwl_priv *priv) +enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; - if (!priv->power_data.adv_tt) - return IWL_TX_MULTI; + if (!priv->thermal_throttle.advanced_tt) + return IWL_ANT_OK_MULTI; restriction = tt->restriction + tt->state; return restriction->tx_stream; } EXPORT_SYMBOL(iwl_tx_ant_restriction); -u8 iwl_rx_ant_restriction(struct iwl_priv *priv) +enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; struct iwl_tt_restriction *restriction; - if (!priv->power_data.adv_tt) - return IWL_RX_MULTI; + if (!priv->thermal_throttle.advanced_tt) + return IWL_ANT_OK_MULTI; restriction = tt->restriction + tt->state; return restriction->rx_stream; } -EXPORT_SYMBOL(iwl_rx_ant_restriction); #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ @@ -361,21 +383,21 @@ EXPORT_SYMBOL(iwl_rx_ant_restriction); static void iwl_tt_check_exit_ct_kill(unsigned long data) { struct iwl_priv *priv = (struct iwl_priv *)data; - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; unsigned long flags; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; if (tt->state == IWL_TI_CT_KILL) { - if (priv->power_data.ct_kill_toggle) { + if (priv->thermal_throttle.ct_kill_toggle) { iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - priv->power_data.ct_kill_toggle = false; + priv->thermal_throttle.ct_kill_toggle = false; } else { iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - priv->power_data.ct_kill_toggle = true; + priv->thermal_throttle.ct_kill_toggle = true; } iwl_read32(priv, CSR_UCODE_DRV_GP1); spin_lock_irqsave(&priv->reg_lock, flags); @@ -386,7 +408,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) /* Reschedule the ct_kill timer to occur in * CT_KILL_EXIT_DURATION seconds to ensure we get a * thermal update */ - mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + + mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + CT_KILL_EXIT_DURATION * HZ); } } @@ -400,7 +422,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, ieee80211_stop_queues(priv->hw); IWL_DEBUG_POWER(priv, "Schedule 5 seconds CT_KILL Timer\n"); - mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + + mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + CT_KILL_EXIT_DURATION * HZ); } else { IWL_DEBUG_POWER(priv, "Wake all queues\n"); @@ -424,9 +446,8 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, */ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; - enum iwl_tt_state new_state; - struct iwl_power_mgr *setting = &priv->power_data; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; + enum iwl_tt_state old_state; #ifdef CONFIG_IWLWIFI_DEBUG if ((tt->tt_previous_temp) && @@ -438,38 +459,28 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) (temp - tt->tt_previous_temp)); } #endif + old_state = tt->state; /* in Celsius */ if (temp >= IWL_MINIMAL_POWER_THRESHOLD) - new_state = IWL_TI_CT_KILL; + tt->state = IWL_TI_CT_KILL; else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2) - new_state = IWL_TI_2; + tt->state = IWL_TI_2; else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1) - new_state = IWL_TI_1; + tt->state = IWL_TI_1; else - new_state = IWL_TI_0; + tt->state = IWL_TI_0; #ifdef CONFIG_IWLWIFI_DEBUG tt->tt_previous_temp = temp; #endif - if (tt->state != new_state) { - if (tt->state == IWL_TI_0) { - tt->sys_power_mode = setting->power_mode; - IWL_DEBUG_POWER(priv, "current power mode: %u\n", - setting->power_mode); - } - switch (new_state) { + if (tt->state != old_state) { + switch (tt->state) { case IWL_TI_0: - /* when system ready to go back to IWL_TI_0 state - * using system power mode instead of TT power mode - * revert back to the orginal power mode which was saved - * before enter Thermal Throttling state - * update priv->power_data.user_power_setting to the - * required power mode to make sure - * iwl_power_update_mode() will update power correctly. + /* + * When the system is ready to go back to IWL_TI_0 + * we only have to call iwl_power_update_mode() to + * do so. */ - priv->power_data.user_power_setting = - tt->sys_power_mode; - tt->tt_power_mode = tt->sys_power_mode; break; case IWL_TI_1: tt->tt_power_mode = IWL_POWER_INDEX_3; @@ -481,24 +492,26 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) tt->tt_power_mode = IWL_POWER_INDEX_5; break; } + mutex_lock(&priv->mutex); if (iwl_power_update_mode(priv, true)) { /* TT state not updated * try again during next temperature read */ + tt->state = old_state; IWL_ERR(priv, "Cannot update power mode, " "TT state not updated\n"); } else { - if (new_state == IWL_TI_CT_KILL) + if (tt->state == IWL_TI_CT_KILL) iwl_perform_ct_kill_task(priv, true); - else if (tt->state == IWL_TI_CT_KILL && - new_state != IWL_TI_CT_KILL) + else if (old_state == IWL_TI_CT_KILL && + tt->state != IWL_TI_CT_KILL) iwl_perform_ct_kill_task(priv, false); - tt->state = new_state; IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", tt->state); IWL_DEBUG_POWER(priv, "Power Index change to %u\n", tt->tt_power_mode); } + mutex_unlock(&priv->mutex); } } @@ -525,7 +538,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) */ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; int i; bool changed = false; enum iwl_tt_state old_state; @@ -570,20 +583,15 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) } if (changed) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - struct iwl_power_mgr *setting = &priv->power_data; if (tt->state >= IWL_TI_1) { - /* if switching from IWL_TI_0 to other TT state - * save previous power setting in tt->sys_power_mode */ - if (old_state == IWL_TI_0) - tt->sys_power_mode = setting->power_mode; /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */ tt->tt_power_mode = IWL_POWER_INDEX_5; if (!iwl_ht_enabled(priv)) /* disable HT */ rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | - RXON_FLG_FAT_PROT_MSK | + RXON_FLG_HT40_PROT_MSK | RXON_FLG_HT_PROT_MSK); else { /* check HT capability and set @@ -593,22 +601,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) } } else { - /* restore system power setting */ - /* the previous power mode was saved in - * tt->sys_power_mode when system move into - * Thermal Throttling state - * set power_data.user_power_setting to the previous - * system power mode to make sure power will get - * updated correctly + /* + * restore system power setting -- it will be + * recalculated automatically. */ - priv->power_data.user_power_setting = - tt->sys_power_mode; - tt->tt_power_mode = tt->sys_power_mode; + /* check HT capability and set * according to the system HT capability * in case get disabled before */ iwl_set_rxon_ht(priv, &priv->current_ht_config); } + mutex_lock(&priv->mutex); if (iwl_power_update_mode(priv, true)) { /* TT state not updated * try again during next temperature read @@ -631,6 +634,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) iwl_perform_ct_kill_task(priv, false); } } + mutex_unlock(&priv->mutex); } } @@ -644,17 +648,21 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) * for advance mode * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state */ -void iwl_tt_enter_ct_kill(struct iwl_priv *priv) +static void iwl_bg_ct_enter(struct work_struct *work) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter); + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + if (!iwl_is_ready(priv)) + return; + if (tt->state != IWL_TI_CT_KILL) { IWL_ERR(priv, "Device reached critical temperature " "- ucode going to sleep!\n"); - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, IWL_MINIMAL_POWER_THRESHOLD); else @@ -662,38 +670,61 @@ void iwl_tt_enter_ct_kill(struct iwl_priv *priv) CT_KILL_THRESHOLD + 1); } } -EXPORT_SYMBOL(iwl_tt_enter_ct_kill); /* Card State Notification indicated out of critical temperature * since Card State Notification will not provide any temperature reading * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state */ -void iwl_tt_exit_ct_kill(struct iwl_priv *priv) +static void iwl_bg_ct_exit(struct work_struct *work) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit); + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + if (!iwl_is_ready(priv)) + return; + /* stop ct_kill_exit_tm timer */ - del_timer_sync(&priv->power_data.ct_kill_exit_tm); + del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); if (tt->state == IWL_TI_CT_KILL) { IWL_ERR(priv, "Device temperature below critical" "- ucode awake!\n"); - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, IWL_REDUCED_PERFORMANCE_THRESHOLD_2); else iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); } } + +void iwl_tt_enter_ct_kill(struct iwl_priv *priv) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n"); + queue_work(priv->workqueue, &priv->ct_enter); +} +EXPORT_SYMBOL(iwl_tt_enter_ct_kill); + +void iwl_tt_exit_ct_kill(struct iwl_priv *priv) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n"); + queue_work(priv->workqueue, &priv->ct_exit); +} EXPORT_SYMBOL(iwl_tt_exit_ct_kill); -void iwl_tt_handler(struct iwl_priv *priv) +static void iwl_bg_tt_work(struct work_struct *work) { + struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work); s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -702,11 +733,20 @@ void iwl_tt_handler(struct iwl_priv *priv) if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) temp = KELVIN_TO_CELSIUS(priv->temperature); - if (!priv->power_data.adv_tt) + if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, temp); else iwl_advance_tt_handler(priv, temp); } + +void iwl_tt_handler(struct iwl_priv *priv) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n"); + queue_work(priv->workqueue, &priv->tt_work); +} EXPORT_SYMBOL(iwl_tt_handler); /* Thermal throttling initialization @@ -716,8 +756,7 @@ EXPORT_SYMBOL(iwl_tt_handler); */ void iwl_tt_initialize(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; - struct iwl_power_mgr *setting = &priv->power_data; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); struct iwl_tt_trans *transaction; @@ -726,11 +765,15 @@ void iwl_tt_initialize(struct iwl_priv *priv) memset(tt, 0, sizeof(struct iwl_tt_mgmt)); tt->state = IWL_TI_0; - tt->sys_power_mode = setting->power_mode; - tt->tt_power_mode = tt->sys_power_mode; - init_timer(&priv->power_data.ct_kill_exit_tm); - priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; - priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; + init_timer(&priv->thermal_throttle.ct_kill_exit_tm); + priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; + priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; + + /* setup deferred ct kill work */ + INIT_WORK(&priv->tt_work, iwl_bg_tt_work); + INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); + INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_6x00: case CSR_HW_REV_TYPE_6x50: @@ -742,7 +785,7 @@ void iwl_tt_initialize(struct iwl_priv *priv) GFP_KERNEL); if (!tt->restriction || !tt->transaction) { IWL_ERR(priv, "Fallback to Legacy Throttling\n"); - priv->power_data.adv_tt = false; + priv->thermal_throttle.advanced_tt = false; kfree(tt->restriction); tt->restriction = NULL; kfree(tt->transaction); @@ -764,12 +807,12 @@ void iwl_tt_initialize(struct iwl_priv *priv) IWL_TI_STATE_MAX; memcpy(tt->restriction, &restriction_range[0], size); - priv->power_data.adv_tt = true; + priv->thermal_throttle.advanced_tt = true; } break; default: IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); - priv->power_data.adv_tt = false; + priv->thermal_throttle.advanced_tt = false; break; } } @@ -778,12 +821,15 @@ EXPORT_SYMBOL(iwl_tt_initialize); /* cleanup thermal throttling management related memory and timer */ void iwl_tt_exit(struct iwl_priv *priv) { - struct iwl_tt_mgmt *tt = &priv->power_data.tt; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; /* stop ct_kill_exit_tm timer if activated */ - del_timer_sync(&priv->power_data.ct_kill_exit_tm); + del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); + cancel_work_sync(&priv->tt_work); + cancel_work_sync(&priv->ct_enter); + cancel_work_sync(&priv->ct_exit); - if (priv->power_data.adv_tt) { + if (priv->thermal_throttle.advanced_tt) { /* free advance thermal throttling memory */ kfree(tt->restriction); tt->restriction = NULL; @@ -796,9 +842,13 @@ EXPORT_SYMBOL(iwl_tt_exit); /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { - iwl_power_init_handle(priv); - priv->power_data.user_power_setting = IWL_POWER_INDEX_1; - /* default to disabled until mac80211 says otherwise */ - priv->power_data.power_disabled = 1; + u16 lctl = iwl_pcie_link_ctl(priv); + + priv->power_data.pci_pm = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN); + + priv->power_data.debug_sleep_level_override = -1; + + memset(&priv->power_data.sleep_cmd, 0, + sizeof(priv->power_data.sleep_cmd)); } EXPORT_SYMBOL(iwl_power_initialize); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 3d49b7a45b7..df6f6a49712 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -28,22 +28,17 @@ #ifndef __iwl_power_setting_h__ #define __iwl_power_setting_h__ -#include <net/mac80211.h> #include "iwl-commands.h" -struct iwl_priv; - #define IWL_ABSOLUTE_ZERO 0 #define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 -/* Tx/Rx restrictions */ -#define IWL_TX_MULTI 0x02 -#define IWL_TX_SINGLE 0x01 -#define IWL_TX_NONE 0x00 -#define IWL_RX_MULTI 0x02 -#define IWL_RX_SINGLE 0x01 -#define IWL_RX_NONE 0x00 +enum iwl_antenna_ok { + IWL_ANT_OK_NONE, + IWL_ANT_OK_SINGLE, + IWL_ANT_OK_MULTI, +}; /* Thermal Throttling State Machine states */ enum iwl_tt_state { @@ -55,27 +50,30 @@ enum iwl_tt_state { }; /** - * struct iwl_tt_restriction - Thermal Throttling restriction table used - * by advance thermal throttling management - * based on the current thermal throttling state, determine - * number of tx/rx streams; and the status of HT operation + * struct iwl_tt_restriction - Thermal Throttling restriction table * @tx_stream: number of tx stream allowed * @is_ht: ht enable/disable * @rx_stream: number of rx stream allowed + * + * This table is used by advance thermal throttling management + * based on the current thermal throttling state, and determines + * the number of tx/rx streams and the status of HT operation. */ struct iwl_tt_restriction { - u8 tx_stream; + enum iwl_antenna_ok tx_stream; + enum iwl_antenna_ok rx_stream; bool is_ht; - u8 rx_stream; }; /** - * struct iwl_tt_trans - Thermal Throttling transaction table; used by - * advance thermal throttling algorithm to determine next - * thermal state to go based on the current temperature + * struct iwl_tt_trans - Thermal Throttling transaction table * @next_state: next thermal throttling mode * @tt_low: low temperature threshold to change state * @tt_high: high temperature threshold to change state + * + * This is used by the advanced thermal throttling algorithm + * to determine the next thermal state to go based on the + * current temperature. */ struct iwl_tt_trans { enum iwl_tt_state next_state; @@ -85,34 +83,36 @@ struct iwl_tt_trans { /** * struct iwl_tt_mgnt - Thermal Throttling Management structure + * @advanced_tt: advanced thermal throttle required * @state: current Thermal Throttling state * @tt_power_mode: Thermal Throttling power mode index * being used to set power level when * when thermal throttling state != IWL_TI_0 * the tt_power_mode should set to different * power mode based on the current tt state - * @sys_power_mode: previous system power mode - * before transition into TT state * @tt_previous_temperature: last measured temperature * @iwl_tt_restriction: ptr to restriction tbl, used by advance * thermal throttling to determine how many tx/rx streams * should be used in tt state; and can HT be enabled or not * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling * state transaction + * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature + * @ct_kill_exit_tm: timer to exit thermal kill */ struct iwl_tt_mgmt { enum iwl_tt_state state; + bool advanced_tt; u8 tt_power_mode; - u8 sys_power_mode; + bool ct_kill_toggle; #ifdef CONFIG_IWLWIFI_DEBUG s32 tt_previous_temp; #endif struct iwl_tt_restriction *restriction; struct iwl_tt_trans *transaction; + struct timer_list ct_kill_exit_tm; }; -enum { - IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */ +enum iwl_power_level { IWL_POWER_INDEX_1, IWL_POWER_INDEX_2, IWL_POWER_INDEX_3, @@ -121,36 +121,16 @@ enum { IWL_POWER_NUM }; -/* Power management (not Tx power) structures */ - -struct iwl_power_vec_entry { - struct iwl_powertable_cmd cmd; - u8 no_dtim; -}; - struct iwl_power_mgr { - struct iwl_power_vec_entry pwr_range_0[IWL_POWER_NUM]; - struct iwl_power_vec_entry pwr_range_1[IWL_POWER_NUM]; - struct iwl_power_vec_entry pwr_range_2[IWL_POWER_NUM]; - u32 dtim_period; - /* final power level that used to calculate final power command */ - u8 power_mode; - u8 user_power_setting; /* set by user through sysfs */ - u8 power_disabled; /* set by mac80211's CONF_PS */ - struct iwl_tt_mgmt tt; /* Thermal Throttling Management */ - bool adv_tt; /* false: legacy mode */ - /* true: advance mode */ - bool ct_kill_toggle; /* use to toggle the CSR bit when - * checking uCode temperature - */ - struct timer_list ct_kill_exit_tm; + struct iwl_powertable_cmd sleep_cmd; + int debug_sleep_level_override; + bool pci_pm; }; int iwl_power_update_mode(struct iwl_priv *priv, bool force); -int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); bool iwl_ht_enabled(struct iwl_priv *priv); -u8 iwl_tx_ant_restriction(struct iwl_priv *priv); -u8 iwl_rx_ant_restriction(struct iwl_priv *priv); +enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv); +enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv); void iwl_tt_enter_ct_kill(struct iwl_priv *priv); void iwl_tt_exit_ct_kill(struct iwl_priv *priv); void iwl_tt_handler(struct iwl_priv *priv); @@ -158,4 +138,6 @@ void iwl_tt_initialize(struct iwl_priv *priv); void iwl_tt_exit(struct iwl_priv *priv); void iwl_power_initialize(struct iwl_priv *priv); +extern bool no_sleep_autoadjust; + #endif /* __iwl_power_setting_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index e002c8b56c4..8150c5c3a16 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -539,13 +539,14 @@ void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", - (int)sizeof(priv->statistics), pkt->len); + (int)sizeof(priv->statistics), + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); change = ((priv->statistics.general.temperature != pkt->u.stats.general.temperature) || ((priv->statistics.flag & - STATISTICS_REPLY_FLG_FAT_MODE_MSK) != - (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK))); + STATISTICS_REPLY_FLG_HT40_MODE_MSK) != + (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); @@ -645,7 +646,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, u32 tsf_low; int rssi; - if (likely(!(iwl_debug_level & IWL_DL_RX))) + if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX))) return; /* MAC header */ @@ -741,18 +742,10 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(IWL_DL_RX, header, length); + iwl_print_hex_dump(priv, IWL_DL_RX, header, length); } #endif -static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->rx_stats[idx].cnt++; - priv->rx_stats[idx].bytes += len; -} - /* * returns non-zero if packet should be dropped */ @@ -861,61 +854,12 @@ static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) } static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, - int include_phy, - struct iwl_rx_mem_buffer *rxb, - struct ieee80211_rx_status *stats) + struct ieee80211_hdr *hdr, + u16 len, + u32 ampdu_status, + struct iwl_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl_rx_phy_res *rx_start = (include_phy) ? - (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : NULL; - struct ieee80211_hdr *hdr; - u16 len; - __le32 *rx_end; - unsigned int skblen; - u32 ampdu_status; - u32 ampdu_status_legacy; - - if (!include_phy && priv->last_phy_res[0]) - rx_start = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; - - if (!rx_start) { - IWL_ERR(priv, "MPDU frame without a PHY data\n"); - return; - } - if (include_phy) { - hdr = (struct ieee80211_hdr *)((u8 *) &rx_start[1] + - rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - - rx_end = (__le32 *)((u8 *) &pkt->u.raw[0] + - sizeof(struct iwl_rx_phy_res) + - rx_start->cfg_phy_cnt + len); - - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; - - hdr = (struct ieee80211_hdr *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_start->byte_count = amsdu->byte_count; - rx_end = (__le32 *) (((u8 *) hdr) + len); - } - - ampdu_status = le32_to_cpu(*rx_end); - skblen = ((u8 *) rx_end - (u8 *) &pkt->u.raw[0]) + sizeof(u32); - - if (!include_phy) { - /* New status scheme, need to translate */ - ampdu_status_legacy = ampdu_status; - ampdu_status = iwl_translate_rx_status(priv, ampdu_status); - } - - /* start from MAC */ - skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); - skb_put(rxb->skb, len); /* end where data ends */ - /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { IWL_DEBUG_DROP_LIMIT(priv, @@ -923,14 +867,16 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, return; } - hdr = (struct ieee80211_hdr *)rxb->skb->data; - - /* in case of HW accelerated crypto and bad decryption, drop */ + /* In case of HW accelerated crypto and bad decryption, drop */ if (!priv->cfg->mod_params->sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; - iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); + /* Resize SKB from mac header to end of packet */ + skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data); + skb_put(rxb->skb, len); + + iwl_update_stats(priv, false, hdr->frame_control, len); memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); ieee80211_rx_irqsafe(priv->hw, rxb->skb); priv->alloc_rxb_skb--; @@ -963,82 +909,80 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status; struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - /* Use phy data (Rx signal strength, etc.) contained within - * this rx packet for legacy frames, - * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ - int include_phy = (pkt->hdr.cmd == REPLY_RX); - struct iwl_rx_phy_res *rx_start = (include_phy) ? - (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : - (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; - __le32 *rx_end; - unsigned int len = 0; + struct iwl_rx_phy_res *phy_res; + __le32 rx_pkt_status; + struct iwl4965_rx_mpdu_res_start *amsdu; + u32 len; + u32 ampdu_status; u16 fc; - u8 network_packet; - - rx_status.mactime = le64_to_cpu(rx_start->timestamp); - rx_status.freq = - ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); - rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; - rx_status.rate_idx = - iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); - if (rx_status.band == IEEE80211_BAND_5GHZ) - rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; - - rx_status.flag = 0; + u32 rate_n_flags; - /* TSF isn't reliable. In order to allow smooth user experience, - * this W/A doesn't propagate it to the mac80211 */ - /*rx_status.flag |= RX_FLAG_TSFT;*/ + /** + * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. + * REPLY_RX: physical layer info is in this buffer + * REPLY_RX_MPDU_CMD: physical layer info was sent in separate + * command and cached in priv->last_phy_res + * + * Here we set up local variables depending on which command is + * received. + */ + if (pkt->hdr.cmd == REPLY_RX) { + phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; + header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) + + phy_res->cfg_phy_cnt); + + len = le16_to_cpu(phy_res->byte_count); + rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + + phy_res->cfg_phy_cnt + len); + ampdu_status = le32_to_cpu(rx_pkt_status); + } else { + if (!priv->last_phy_res[0]) { + IWL_ERR(priv, "MPDU frame without cached PHY data\n"); + return; + } + phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; + amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; + header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); + len = le16_to_cpu(amsdu->byte_count); + rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); + ampdu_status = iwl_translate_rx_status(priv, + le32_to_cpu(rx_pkt_status)); + } - if ((unlikely(rx_start->cfg_phy_cnt > 20))) { + if ((unlikely(phy_res->cfg_phy_cnt > 20))) { IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", - rx_start->cfg_phy_cnt); + phy_res->cfg_phy_cnt); return; } - if (!include_phy) { - if (priv->last_phy_res[0]) - rx_start = (struct iwl_rx_phy_res *) - &priv->last_phy_res[1]; - else - rx_start = NULL; - } - - if (!rx_start) { - IWL_ERR(priv, "MPDU frame without a PHY data\n"); + if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || + !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { + IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", + le32_to_cpu(rx_pkt_status)); return; } - if (include_phy) { - header = (struct ieee80211_hdr *)((u8 *) &rx_start[1] - + rx_start->cfg_phy_cnt); - - len = le16_to_cpu(rx_start->byte_count); - rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + - sizeof(struct iwl_rx_phy_res) + len); - } else { - struct iwl4965_rx_mpdu_res_start *amsdu = - (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; + /* This will be used in several places later */ + rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); - header = (void *)(pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start)); - len = le16_to_cpu(amsdu->byte_count); - rx_end = (__le32 *) (pkt->u.raw + - sizeof(struct iwl4965_rx_mpdu_res_start) + len); - } + /* rx_status carries information about the packet to mac80211 */ + rx_status.mactime = le64_to_cpu(phy_res->timestamp); + rx_status.freq = + ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel)); + rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + rx_status.rate_idx = + iwl_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); + rx_status.flag = 0; - if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || - !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { - IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", - le32_to_cpu(*rx_end)); - return; - } + /* TSF isn't reliable. In order to allow smooth user experience, + * this W/A doesn't propagate it to the mac80211 */ + /*rx_status.flag |= RX_FLAG_TSFT;*/ - priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); + priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); /* Find max signal strength (dBm) among 3 antenna/receiver chains */ - rx_status.signal = iwl_calc_rssi(priv, rx_start); + rx_status.signal = iwl_calc_rssi(priv, phy_res); /* Meaningful noise values are available only from beacon statistics, * which are gathered only when associated, and indicate noise @@ -1058,11 +1002,12 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (!iwl_is_associated(priv)) priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - /* Set "1" to report good data frames in groups of 100 */ #ifdef CONFIG_IWLWIFI_DEBUG - if (unlikely(iwl_debug_level & IWL_DL_RX)) - iwl_dbg_report_frame(priv, rx_start, len, header, 1); + /* Set "1" to report good data frames in groups of 100 */ + if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) + iwl_dbg_report_frame(priv, phy_res, len, header, 1); #endif + iwl_dbg_log_rx_data_frame(priv, len, header); IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", rx_status.signal, rx_status.noise, rx_status.qual, (unsigned long long)rx_status.mactime); @@ -1080,18 +1025,26 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, * new 802.11n radiotap field "RX chains" that is defined * as a bitmask. */ - rx_status.antenna = le16_to_cpu(rx_start->phy_flags & - RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + rx_status.antenna = + le16_to_cpu(phy_res->phy_flags & RX_RES_PHY_FLAGS_ANTENNA_MSK) + >> RX_RES_PHY_FLAGS_ANTENNA_POS; /* set the preamble flag if appropriate */ - if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) rx_status.flag |= RX_FLAG_SHORTPRE; - network_packet = iwl_is_network_packet(priv, header); - if (network_packet) { + /* Set up the HT phy flags */ + if (rate_n_flags & RATE_MCS_HT_MSK) + rx_status.flag |= RX_FLAG_HT; + if (rate_n_flags & RATE_MCS_HT40_MSK) + rx_status.flag |= RX_FLAG_40MHZ; + if (rate_n_flags & RATE_MCS_SGI_MSK) + rx_status.flag |= RX_FLAG_SHORT_GI; + + if (iwl_is_network_packet(priv, header)) { priv->last_rx_rssi = rx_status.signal; priv->last_beacon_time = priv->ucode_beacon_time; - priv->last_tsf = le64_to_cpu(rx_start->timestamp); + priv->last_tsf = le64_to_cpu(phy_res->timestamp); } fc = le16_to_cpu(header->frame_control); @@ -1103,8 +1056,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, header->addr2); /* fall through */ default: - iwl_pass_packet_to_mac80211(priv, include_phy, rxb, - &rx_status); + iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, + rxb, &rx_status); break; } diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index c4c916df4a4..4f3a108fa99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -796,7 +796,8 @@ void iwl_bg_abort_scan(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); - if (!iwl_is_ready(priv)) + if (!test_bit(STATUS_READY, &priv->status) || + !test_bit(STATUS_GEO_CONFIGURED, &priv->status)) return; mutex_lock(&priv->mutex); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index efcae0d5e19..a2b9ec82b96 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -214,10 +214,10 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, sta_flags |= cpu_to_le32( (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); - if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) - sta_flags |= STA_FLG_FAT_EN_MSK; + if (iwl_is_ht40_tx_allowed(priv, sta_ht_inf)) + sta_flags |= STA_FLG_HT40_EN_MSK; else - sta_flags &= ~STA_FLG_FAT_EN_MSK; + sta_flags &= ~STA_FLG_HT40_EN_MSK; priv->stations[index].sta.station_flags = sta_flags; done: @@ -520,7 +520,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) struct iwl_host_cmd cmd = { .id = REPLY_WEPKEY, .data = wep_cmd, - .flags = CMD_ASYNC, + .flags = CMD_SYNC, }; memset(wep_cmd, 0, cmd_size + @@ -1088,7 +1088,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) IWL_DEBUG_DROP(priv, "Station %pM not in station map. " "Defaulting to broadcast...\n", hdr->addr1); - iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; default: diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 288b871e974..a7422e52d88 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -566,62 +566,81 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, - __le16 fc, int sta_id, - int is_hcca) + __le16 fc, int is_hcca) { - u32 rate_flags = 0; + u32 rate_flags; int rate_idx; - u8 rts_retry_limit = 0; - u8 data_retry_limit = 0; + u8 rts_retry_limit; + u8 data_retry_limit; u8 rate_plcp; - rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff, - IWL_RATE_COUNT - 1); - - rate_plcp = iwl_rates[rate_idx].plcp; - - rts_retry_limit = (is_hcca) ? - RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; - - if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) - rate_flags |= RATE_MCS_CCK_MSK; - - - if (ieee80211_is_probe_resp(fc)) { - data_retry_limit = 3; - if (data_retry_limit < rts_retry_limit) - rts_retry_limit = data_retry_limit; - } else - data_retry_limit = IWL_DEFAULT_TX_RETRY; - + /* Set retry limit on DATA packets and Probe Responses*/ if (priv->data_retry_limit != -1) data_retry_limit = priv->data_retry_limit; + else if (ieee80211_is_probe_resp(fc)) + data_retry_limit = 3; + else + data_retry_limit = IWL_DEFAULT_TX_RETRY; + tx_cmd->data_retry_limit = data_retry_limit; + /* Set retry limit on RTS packets */ + rts_retry_limit = (is_hcca) ? RTS_HCCA_RETRY_LIMIT : + RTS_DFAULT_RETRY_LIMIT; + if (data_retry_limit < rts_retry_limit) + rts_retry_limit = data_retry_limit; + tx_cmd->rts_retry_limit = rts_retry_limit; + /* DATA packets will use the uCode station table for rate/antenna + * selection */ if (ieee80211_is_data(fc)) { tx_cmd->initial_rate_index = 0; tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; - } else { - switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { - case cpu_to_le16(IEEE80211_STYPE_AUTH): - case cpu_to_le16(IEEE80211_STYPE_DEAUTH): - case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): - case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): - if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) { - tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK; - } - break; - default: - break; - } + return; + } - priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); - rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); + /** + * If the current TX rate stored in mac80211 has the MCS bit set, it's + * not really a TX rate. Thus, we use the lowest supported rate for + * this band. Also use the lowest supported rate if the stored rate + * index is invalid. + */ + rate_idx = info->control.rates[0].idx; + if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS || + (rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY)) + rate_idx = rate_lowest_index(&priv->bands[info->band], + info->control.sta); + /* For 5 GHZ band, remap mac80211 rate indices into driver indices */ + if (info->band == IEEE80211_BAND_5GHZ) + rate_idx += IWL_FIRST_OFDM_RATE; + /* Get PLCP rate for tx_cmd->rate_n_flags */ + rate_plcp = iwl_rates[rate_idx].plcp; + /* Zero out flags for this packet */ + rate_flags = 0; + + /* Set CCK flag as needed */ + if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) + rate_flags |= RATE_MCS_CCK_MSK; + + /* Set up RTS and CTS flags for certain packets */ + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_AUTH): + case cpu_to_le16(IEEE80211_STYPE_DEAUTH): + case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): + case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): + if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) { + tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK; + } + break; + default: + break; } - tx_cmd->rts_retry_limit = rts_retry_limit; - tx_cmd->data_retry_limit = data_retry_limit; + /* Set up antennas */ + priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); + rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); + + /* Set the rate in the TX cmd */ tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags); } @@ -668,14 +687,6 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, } } -static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len) -{ - /* 0 - mgmt, 1 - cnt, 2 - data */ - int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; - priv->tx_stats[idx].cnt++; - priv->tx_stats[idx].bytes += len; -} - /* * start REPLY_TX command process */ @@ -709,12 +720,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) goto drop_unlock; } - if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == - IWL_INVALID_RATE) { - IWL_ERR(priv, "ERROR: No TX rate available.\n"); - goto drop_unlock; - } - fc = hdr->frame_control; #ifdef CONFIG_IWLWIFI_DEBUG @@ -726,10 +731,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); #endif - /* drop all data frame if we are not associated */ + /* drop all non-injected data frame if we are not associated */ if (ieee80211_is_data(fc) && - (!iwl_is_monitor_mode(priv) || - !(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */ + !(info->flags & IEEE80211_TX_CTL_INJECTED) && (!iwl_is_associated(priv) || ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) || !priv->assoc_station_added)) { @@ -740,7 +744,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ - sta_id = iwl_get_sta_id(priv, hdr); + if (info->flags & IEEE80211_TX_CTL_INJECTED) + sta_id = priv->hw_params.bcast_sta_id; + else + sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", hdr->addr1); @@ -753,6 +760,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + if (unlikely(tid >= MAX_TID_COUNT)) + goto drop_unlock; seq_number = priv->stations[sta_id].tid[tid].seq_number; seq_number &= IEEE80211_SCTL_SEQ; hdr->seq_ctrl = hdr->seq_ctrl & @@ -808,12 +817,12 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* TODO need this for burst mode later on */ iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id); + iwl_dbg_log_tx_data_frame(priv, len, hdr); /* set is_hcca to 0; it probably will never be implemented */ - iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); - - iwl_update_tx_stats(priv, le16_to_cpu(fc), len); + iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, 0); + iwl_update_stats(priv, true, fc, len); /* * Use the first empty entry in this queue's command buffer array * to contain the Tx command and MAC header concatenated together @@ -884,8 +893,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", le16_to_cpu(out_cmd->hdr.sequence)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); /* Set up entry for this TFD in Tx byte-count array */ if (info->flags & IEEE80211_TX_CTL_AMPDU) @@ -1246,6 +1255,9 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) return -EINVAL; } + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) tx_fifo_id = default_tid_to_tx_fifo[tid]; else diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5ded8983b91..2238c9f2018 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -518,9 +518,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); #endif - /* drop all data frame if we are not associated */ + /* drop all non-injected data frame if we are not associated */ if (ieee80211_is_data(fc) && - (!iwl_is_monitor_mode(priv)) && /* packet injection */ + !(info->flags & IEEE80211_TX_CTL_INJECTED) && (!iwl_is_associated(priv) || ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) { IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n"); @@ -532,7 +532,10 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ - sta_id = iwl_get_sta_id(priv, hdr); + if (info->flags & IEEE80211_TX_CTL_INJECTED) + sta_id = priv->hw_params.bcast_sta_id; + else + sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", hdr->addr1); @@ -544,6 +547,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + if (unlikely(tid >= MAX_TID_COUNT)) + goto drop; seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | @@ -598,7 +603,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) len = (u16)skb->len; tx->len = cpu_to_le16(len); - + iwl_dbg_log_tx_data_frame(priv, len, hdr); + iwl_update_stats(priv, true, fc, len); tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; @@ -614,8 +620,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", le16_to_cpu(out_cmd->hdr.sequence)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags)); - iwl_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr, + iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx)); + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr, ieee80211_hdrlen(fc)); /* @@ -1367,7 +1373,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) fill_rx = 1; /* Rx interrupt, but nothing sent from uCode */ if (i == r) - IWL_DEBUG(priv, IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); + IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); while (i != r) { rxb = rxq->queue[i]; @@ -1398,15 +1404,13 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) * handle those that need handling via function in * rx_handlers table. See iwl3945_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { - IWL_DEBUG(priv, IWL_DL_HCMD | IWL_DL_RX | IWL_DL_ISR, - "r = %d, i = %d, %s, 0x%02x\n", r, i, + IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; } else { /* No handling needed */ - IWL_DEBUG(priv, IWL_DL_HCMD | IWL_DL_RX | IWL_DL_ISR, - "r %d i %d No handler needed for %s, 0x%02x\n", + IWL_DEBUG_RX(priv, "r %d i %d No handler needed for %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); } @@ -1646,7 +1650,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { + if (iwl_get_debug_level(priv) & IWL_DL_ISR) { /* just for debug */ inta_mask = iwl_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", @@ -1681,7 +1685,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " @@ -1760,7 +1764,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { + if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { inta = iwl_read32(priv, CSR_INT); inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); @@ -3311,14 +3315,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * * See the level definitions in iwl for details. * - * FIXME This file can be deprecated as the module parameter is - * writable and users can thus also change the debug level - * using the /sys/module/iwl3945/parameters/debug file. + * The debug_level being managed using sysfs below is a per device debug + * level that is used instead of the global debug level if it (the per + * device debug level) is set. */ static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - return sprintf(buf, "0x%08X\n", iwl_debug_level); + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); } static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, @@ -3331,9 +3336,12 @@ static ssize_t store_debug_level(struct device *d, ret = strict_strtoul(buf, 0, &val); if (ret) IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf); - else - iwl_debug_level = val; - + else { + priv->debug_level = val; + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, + "Not enough memory to generate traffic log\n"); + } return strnlen(buf, count); } @@ -3549,65 +3557,6 @@ static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, store_retry_rate); -static ssize_t store_power_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int ret; - unsigned long mode; - - - mutex_lock(&priv->mutex); - - ret = strict_strtoul(buf, 10, &mode); - if (ret) - goto out; - - ret = iwl_power_set_user_mode(priv, mode); - if (ret) { - IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n"); - goto out; - } - ret = count; - - out: - mutex_unlock(&priv->mutex); - return ret; -} - -static ssize_t show_power_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int level = priv->power_data.power_mode; - char *p = buf; - - p += sprintf(p, "%d\n", level); - return p - buf + 1; -} - -static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, - show_power_level, store_power_level); - -#define MAX_WX_STRING 80 - -/* Values are in microsecond */ -static const s32 timeout_duration[] = { - 350000, - 250000, - 75000, - 37000, - 25000, -}; -static const s32 period_duration[] = { - 400000, - 700000, - 1000000, - 1000000, - 1000000 -}; - static ssize_t show_channels(struct device *d, struct device_attribute *attr, char *buf) { @@ -3784,7 +3733,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT &dev_attr_measurement.attr, #endif - &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, @@ -3849,8 +3797,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->qos_data.qos_cap.val = 0; priv->rates_mask = IWL_RATES_MASK; - /* If power management is turned on, default to CAM mode */ - priv->power_mode = IWL_POWER_MODE_CAM; priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { @@ -3897,7 +3843,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | - IEEE80211_HW_SPECTRUM_MGMT; + IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | @@ -3905,6 +3853,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) hw->wiphy->custom_regulatory = true; + /* Firmware does not support this */ + hw->wiphy->disable_beacon_hints = true; + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; /* we create the 802.11 header and a zero-length SSID element */ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; @@ -3972,6 +3923,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e #ifdef CONFIG_IWLWIFI_DEBUG atomic_set(&priv->restrict_refcnt, 0); #endif + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, "Not enough memory to generate traffic log\n"); /*************************** * 2. Initializing PCI bus @@ -4134,6 +4087,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_disable_device(pdev); out_ieee80211_free_hw: ieee80211_free_hw(priv->hw); + iwl_free_traffic_mem(priv); out: return err; } @@ -4189,6 +4143,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) * until now... */ destroy_workqueue(priv->workqueue); priv->workqueue = NULL; + iwl_free_traffic_mem(priv); free_irq(pdev->irq, priv); pci_disable_msi(pdev); |