From 85fecff155ed2ba0cccd618ab92d5b4e7d69cd5d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:07 -0700 Subject: iwlwifi: modify LED blink index table Modify LED blink index table to include 1Mbps. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-led.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index f420c99e7240..41addd1c7261 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -65,9 +65,9 @@ static const struct { {70, 65, 65}, {50, 75, 75}, {20, 85, 85}, - {15, 95, 95 }, - {10, 110, 110}, - {5, 130, 130}, + {10, 95, 95}, + {5, 110, 110}, + {1, 130, 130}, {0, 167, 167}, /* SOLID_ON */ {-1, IWL_LED_SOLID, 0} -- cgit v1.2.3 From 1b07a1307250e55fe00c076b33d0ab5ac088a489 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:09 -0700 Subject: iwlwifi: remove un-supported eeprom parameters Remove few of the parameters not used and no longer valid in EEPROM. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 6b68db7b1b81..90e2b4ea2606 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -370,12 +370,10 @@ struct iwl_eeprom_calib_info { #define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ #define EEPROM_VERSION (2*0x44) /* 2 bytes */ #define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ -#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ #define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ #define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ #define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */ #define EEPROM_3945_M_VERSION (2*0x4A) /* 1 bytes */ -#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ /* The following masks are to be applied on EEPROM_RADIO_CONFIG */ #define EEPROM_RF_CFG_TYPE_MSK(x) (x & 0x3) /* bits 0-1 */ -- cgit v1.2.3 From 9371d4ed79c1c2efefa00226f7f6b95e0e0b8f2b Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:10 -0700 Subject: iwlwifi: separate nic_config for different NIC Different NIC has different requirements for configuration. Currently all 5000 series hardware and later share the same configuration function even though they do not need the same configurations. Fix this by separating the needed configuration actions for each hardware model. .5000 series: L1-ASPM H/W bug work-around configure radio write CSR_HW_IF_CONFIG_REG for uCode use work-around for NIC get stuck after early PCIe power off .1000 series: write CSR_HW_IF_CONFIG_REG for uCode use setting digital SVR for 1000 card to 1.32V .6000 series: configure radio write CSR_HW_IF_CONFIG_REG for uCode use write CSR_GP_DRIVER_REG to indicate radio sku Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 5 ++++- drivers/net/wireless/iwlwifi/iwl-5000.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 16 +++++++++++++++- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 7 ++++++- 4 files changed, 27 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 2716b91ba9fa..89f360befc30 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -76,7 +76,10 @@ static void iwl1000_set_ct_threshold(struct iwl_priv *priv) /* NIC configuration for 1000 series */ static void iwl1000_nic_config(struct iwl_priv *priv) { - iwl5000_nic_config(priv); + /* set CSR_HW_CONFIG_REG for uCode use */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); /* Setting digital SVR for 1000 card to 1.32V */ /* locking is acquired in iwl_set_bits_mask_prph() function */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index eb08f4411000..d312ef03245f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -198,7 +198,7 @@ out: } -/* NIC configuration for 5000 series and up */ +/* NIC configuration for 5000 series */ void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; @@ -221,7 +221,7 @@ void iwl5000_nic_config(struct iwl_priv *priv) radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); /* write radio config values to register */ - if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_5000_RF_CFG_TYPE_MAX) + if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_RF_CONFIG_TYPE_MAX) iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | EEPROM_RF_CFG_STEP_MSK(radio_cfg) | diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c295b8ee9228..37b3e2086633 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -71,7 +71,21 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) /* NIC configuration for 6000 series */ static void iwl6000_nic_config(struct iwl_priv *priv) { - iwl5000_nic_config(priv); + u16 radio_cfg; + + radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); + + /* write radio config values to register */ + if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | + EEPROM_RF_CFG_STEP_MSK(radio_cfg) | + EEPROM_RF_CFG_DASH_MSK(radio_cfg)); + + /* set CSR_HW_CONFIG_REG for uCode use */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); /* no locking required for register write */ if (priv->cfg->pa_type == IWL_PA_HYBRID) { diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 90e2b4ea2606..61794eb3d689 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -385,7 +385,12 @@ struct iwl_eeprom_calib_info { #define EEPROM_3945_RF_CFG_TYPE_MAX 0x0 #define EEPROM_4965_RF_CFG_TYPE_MAX 0x1 -#define EEPROM_5000_RF_CFG_TYPE_MAX 0x3 + +/* Radio Config for 5000 and up */ +#define EEPROM_RF_CONFIG_TYPE_R3x3 0x0 +#define EEPROM_RF_CONFIG_TYPE_R2x2 0x1 +#define EEPROM_RF_CONFIG_TYPE_R1x2 0x2 +#define EEPROM_RF_CONFIG_TYPE_MAX 0x3 /* * Per-channel regulatory data. -- cgit v1.2.3 From f3a2a42470c1c362b9a7b4e933a15a274d4b090e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:11 -0700 Subject: iwlwifi: separate set_hw_params function for 6000 series Separate set_hw_params() function for 6000 series from 5000/1000 series because: 1) 6000 series use different set of sensitivity range table 2) 6000 series has different uCode image size Also include the new sensitivity parameters needed by sensitivity algorithm. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 12 +----- drivers/net/wireless/iwlwifi/iwl-6000.c | 71 +++++++++++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-calib.c | 2 +- 3 files changed, 73 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d312ef03245f..e1b378528c72 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -833,16 +833,8 @@ int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { - case CSR_HW_REV_TYPE_6x00: - case CSR_HW_REV_TYPE_6x50: - priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; - priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; - break; - default: - priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; - priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE; - } + priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE; priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 37b3e2086633..4b3fb4095678 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -44,6 +44,7 @@ #include "iwl-sta.h" #include "iwl-helpers.h" #include "iwl-5000-hw.h" +#include "iwl-6000-hw.h" /* Highest firmware API version supported */ #define IWL6000_UCODE_API_MAX 4 @@ -100,8 +101,76 @@ static void iwl6000_nic_config(struct iwl_priv *priv) /* else do nothing, uCode configured */ } +static struct iwl_sensitivity_ranges iwl6000_sensitivity = { + .min_nrg_cck = 97, + .max_nrg_cck = 0, /* not used, set to 0 */ + .auto_corr_min_ofdm = 80, + .auto_corr_min_ofdm_mrc = 128, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 192, + + .auto_corr_max_ofdm = 145, + .auto_corr_max_ofdm_mrc = 232, + .auto_corr_max_ofdm_x1 = 145, + .auto_corr_max_ofdm_mrc_x1 = 232, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 175, + .auto_corr_min_cck_mrc = 160, + .auto_corr_max_cck_mrc = 310, + .nrg_th_cck = 97, + .nrg_th_ofdm = 100, +}; + +static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) +{ + if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || + (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { + IWL_ERR(priv, + "invalid queues_num, should be between %d and %d\n", + IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES); + return -EINVAL; + } + + priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; + priv->hw_params.scd_bc_tbls_size = + IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); + priv->hw_params.tfd_size = sizeof(struct iwl_tfd); + priv->hw_params.max_stations = IWL5000_STATION_COUNT; + priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; + + priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; + + priv->hw_params.max_bsm_size = 0; + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; + + priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); + priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; + priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; + + if (priv->cfg->ops->lib->temp_ops.set_ct_kill) + priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); + + /* Set initial sensitivity parameters */ + /* Set initial calibration set */ + priv->hw_params.sens = &iwl6000_sensitivity; + priv->hw_params.calib_init_cfg = + BIT(IWL_CALIB_XTAL) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_TX_IQ_PERD) | + BIT(IWL_CALIB_BASE_BAND); + + return 0; +} + static struct iwl_lib_ops iwl6000_lib = { - .set_hw_params = iwl5000_hw_set_hw_params, + .set_hw_params = iwl6000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, .txq_set_sched = iwl5000_txq_set_sched, diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index c4b565a2de94..6e73317c3b40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -516,7 +516,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv) for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) data->nrg_silence_rssi[i] = 0; - data->auto_corr_ofdm = 90; + data->auto_corr_ofdm = ranges->auto_corr_min_ofdm; data->auto_corr_ofdm_mrc = ranges->auto_corr_min_ofdm_mrc; data->auto_corr_ofdm_x1 = ranges->auto_corr_min_ofdm_x1; data->auto_corr_ofdm_mrc_x1 = ranges->auto_corr_min_ofdm_mrc_x1; -- cgit v1.2.3 From c812ee24855e20f43cf211e51e3eb53fe6dc6f1d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 11 Sep 2009 10:38:13 -0700 Subject: iwlwifi: clean up ht config a little is_ht can be bool instead of u8, and there's no need to use IWL_CHANNEL_WIDTH_* constants in supported_chan_width when that could just be named is_40mhz instead. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 14 +++++--------- drivers/net/wireless/iwlwifi/iwl-dev.h | 7 ++----- 2 files changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 484d5c1a7312..c09475105c52 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -636,8 +636,7 @@ u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, { struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; - if ((!iwl_ht_conf->is_ht) || - (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ)) + if (!iwl_ht_conf->is_ht || !iwl_ht_conf->is_40mhz) return 0; /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 @@ -2619,21 +2618,18 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) 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; + ht_conf->is_40mhz = true; } 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; + ht_conf->is_40mhz = true; } else { ht_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; - ht_conf->supported_chan_width = - IWL_CHANNEL_WIDTH_20MHZ; + ht_conf->is_40mhz = false; } } else - ht_conf->supported_chan_width = IWL_CHANNEL_WIDTH_20MHZ; + ht_conf->is_40mhz = false; /* 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; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 028d50599550..961d53440034 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -504,8 +504,8 @@ union iwl_ht_rate_supp { struct iwl_ht_info { /* self configuration data */ - u8 is_ht; - u8 supported_chan_width; + bool is_ht; + bool is_40mhz; u8 sm_ps; struct ieee80211_mcs_info mcs; /* BSS related data */ @@ -726,9 +726,6 @@ struct iwl_dma_ptr { size_t size; }; -#define IWL_CHANNEL_WIDTH_20MHZ 0 -#define IWL_CHANNEL_WIDTH_40MHZ 1 - #define IWL_OPERATION_MODE_AUTO 0 #define IWL_OPERATION_MODE_HT_ONLY 1 #define IWL_OPERATION_MODE_MIXED 2 -- cgit v1.2.3 From f2d0d0e2bab7a325071dbaba3bef51c90868e1e6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:14 -0700 Subject: iwlwifi: Adjust blink rate to compensate Clock difference Adjust led blink rate to compensate on a MAC Clock difference on every HW. Led blink rate analysis showed an average deviation of 0% on 3945, 5% on 4965 HW and 20% on 5000 series and up. Need to compensate on the led on/off time per HW according to the deviation to achieve the desired led frequency The calculation is: (100-averageDeviation)/100 * blinkTime For code efficiency the calculation will be: compensation = (100 - averageDeviation) * 64 / 100 NewBlinkTime = (compensation * BlinkTime) / 64 Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + drivers/net/wireless/iwlwifi/iwl-3945.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 6 ++++++ drivers/net/wireless/iwlwifi/iwl-6000.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl-core.h | 4 ++++ drivers/net/wireless/iwlwifi/iwl-led.c | 33 +++++++++++++++++++++++++++++++-- 7 files changed, 50 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 89f360befc30..1dd8db2f6f23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -164,5 +164,6 @@ struct iwl_cfg iwl1000_bgn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, .ht_greenfield_support = true, + .led_compensation = 51, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e70c5b0af364..33e40c21eb72 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2894,6 +2894,7 @@ static struct iwl_cfg iwl3945_bg_cfg = { .mod_params = &iwl3945_mod_params, .use_isr_legacy = true, .ht_greenfield_support = false, + .led_compensation = 64, }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2908,6 +2909,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { .mod_params = &iwl3945_mod_params, .use_isr_legacy = true, .ht_greenfield_support = false, + .led_compensation = 64, }; struct pci_device_id iwl3945_hw_card_ids[] = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a22a0501c190..2500ab2e1d91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2355,6 +2355,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .use_isr_legacy = true, .ht_greenfield_support = false, .broken_powersave = true, + .led_compensation = 61, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index e1b378528c72..c81fd4bc32b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1656,6 +1656,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl5100_bg_cfg = { @@ -1673,6 +1674,7 @@ struct iwl_cfg iwl5100_bg_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -1690,6 +1692,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -1707,6 +1710,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1724,6 +1728,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1741,6 +1746,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; 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 4b3fb4095678..48b2b7d2170c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -258,6 +258,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .ht_greenfield_support = true, + .led_compensation = 51, }; /* @@ -281,6 +282,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -301,6 +303,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -321,6 +324,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -341,6 +345,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .ht_greenfield_support = true, + .led_compensation = 51, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index e50103a956b1..79ea42531e28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -213,6 +213,9 @@ struct iwl_mod_params { * @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 + * @led_compensation: compensate on the led on/off time per HW according + * to the deviation to achieve the desired led frequency. + * The detail algorithm is described in iwl-led.c * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -255,6 +258,7 @@ struct iwl_cfg { const bool shadow_ram_support; const bool ht_greenfield_support; const bool broken_powersave; + u16 led_compensation; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 41addd1c7261..f547233c5b79 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -78,6 +78,29 @@ static const struct { #define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */ #define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) +/* + * Adjust led blink rate to compensate on a MAC Clock difference on every HW + * Led blink rate analysis showed an average deviation of 0% on 3945, + * 5% on 4965 HW and 20% on 5000 series and up. + * Need to compensate on the led on/off time per HW according to the deviation + * to achieve the desired led frequency + * The calculation is: (100-averageDeviation)/100 * blinkTime + * For code efficiency the calculation will be: + * compensation = (100 - averageDeviation) * 64 / 100 + * NewBlinkTime = (compensation * BlinkTime) / 64 + */ +static inline u8 iwl_blink_compensation(struct iwl_priv *priv, + u8 time, u16 compensation) +{ + if (!compensation) { + IWL_ERR(priv, "undefined blink compensation: " + "use pre-defined blinking time\n"); + return time; + } + + return (u8)((time * compensation) >> 6); +} + /* [0-256] -> [0..8] FIXME: we need [0..10] */ static inline int iwl_brightness_to_idx(enum led_brightness brightness) { @@ -114,8 +137,14 @@ static int iwl_led_pattern(struct iwl_priv *priv, int led_id, BUG_ON(idx > IWL_MAX_BLINK_TBL); - led_cmd.on = blink_tbl[idx].on_time; - led_cmd.off = blink_tbl[idx].off_time; + IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n", + priv->cfg->led_compensation); + led_cmd.on = + iwl_blink_compensation(priv, blink_tbl[idx].on_time, + priv->cfg->led_compensation); + led_cmd.off = + iwl_blink_compensation(priv, blink_tbl[idx].off_time, + priv->cfg->led_compensation); return iwl_send_led_cmd(priv, &led_cmd); } -- cgit v1.2.3 From fad95bf59bf14f72e7d45d3887044e88b8584637 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 11 Sep 2009 10:38:15 -0700 Subject: iwlwifi: clean up ht config naming Daniel Halperin pointed out that the naming here is rather inconsistent with at least 3 different names being used for one thing in different contexts. Rename the struct to iwl_ht_config (rather than iwl_ht_info) and use ht_conf as a variable for it. Signed-off-by: Johannes Berg Acked-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 48 +++++++++++++++---------------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +-- 4 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 346dc06fa7b7..18af37c964cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -662,7 +662,7 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, * 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) + struct iwl_ht_config *ht_conf) { return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && !(ht_conf->non_GF_STA_present); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c09475105c52..9d01fde92cc6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -634,9 +634,9 @@ static u8 iwl_is_channel_extension(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; + struct iwl_ht_config *ht_conf = &priv->current_ht_config; - if (!iwl_ht_conf->is_ht || !iwl_ht_conf->is_40mhz) + if (!ht_conf->is_ht || !ht_conf->is_40mhz) return 0; /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 @@ -652,7 +652,7 @@ u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, #endif return iwl_is_channel_extension(priv, priv->band, le16_to_cpu(priv->staging_rxon.channel), - iwl_ht_conf->extension_chan_offset); + ht_conf->extension_chan_offset); } EXPORT_SYMBOL(iwl_is_ht40_tx_allowed); @@ -876,11 +876,11 @@ u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rate_get_lowest_plcp); -void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) +void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - if (!ht_info->is_ht) { + if (!ht_conf->is_ht) { rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | RXON_FLG_HT40_PROT_MSK | @@ -891,7 +891,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) /* FIXME: if the definition of ht_protection changed, the "translation" * will be needed for rxon->flags */ - rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); + rxon->flags |= cpu_to_le32(ht_conf->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); /* Set up channel bandwidth: * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ @@ -900,10 +900,10 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); if (iwl_is_ht40_tx_allowed(priv, NULL)) { /* pure ht40 */ - if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { + if (ht_conf->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; /* Note: control channel is opposite of extension channel */ - switch (ht_info->extension_chan_offset) { + switch (ht_conf->extension_chan_offset) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; break; @@ -913,7 +913,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) } } else { /* Note: control channel is opposite of extension channel */ - switch (ht_info->extension_chan_offset) { + switch (ht_conf->extension_chan_offset) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; @@ -939,11 +939,11 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) IWL_DEBUG_ASSOC(priv, "supported HT rate 0x%X 0x%X 0x%X " "rxon flags 0x%X operation mode :0x%X " "extension channel offset 0x%x\n", - ht_info->mcs.rx_mask[0], - ht_info->mcs.rx_mask[1], - ht_info->mcs.rx_mask[2], - le32_to_cpu(rxon->flags), ht_info->ht_protection, - ht_info->extension_chan_offset); + ht_conf->mcs.rx_mask[0], + ht_conf->mcs.rx_mask[1], + ht_conf->mcs.rx_mask[2], + le32_to_cpu(rxon->flags), ht_conf->ht_protection, + ht_conf->extension_chan_offset); return; } EXPORT_SYMBOL(iwl_set_rxon_ht); @@ -2228,13 +2228,13 @@ EXPORT_SYMBOL(iwl_mac_conf_tx); static void iwl_ht_conf(struct iwl_priv *priv, struct ieee80211_bss_conf *bss_conf) { - struct ieee80211_sta_ht_cap *ht_conf; - struct iwl_ht_info *iwl_conf = &priv->current_ht_config; + struct iwl_ht_config *ht_conf = &priv->current_ht_config; + struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta *sta; IWL_DEBUG_MAC80211(priv, "enter: \n"); - if (!iwl_conf->is_ht) + if (!ht_conf->is_ht) return; @@ -2250,15 +2250,15 @@ static void iwl_ht_conf(struct iwl_priv *priv, rcu_read_unlock(); return; } - ht_conf = &sta->ht_cap; + ht_cap = &sta->ht_cap; - iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); + ht_conf->sm_ps = (u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS) >> 2); - memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); + memcpy(&ht_conf->mcs, &ht_cap->mcs, 16); - iwl_conf->ht_protection = + ht_conf->ht_protection = bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; - iwl_conf->non_GF_STA_present = + ht_conf->non_GF_STA_present = !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); rcu_read_unlock(); @@ -2568,7 +2568,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; + struct iwl_ht_config *ht_conf = &priv->current_ht_config; unsigned long flags = 0; int ret = 0; u16 ch; @@ -2735,7 +2735,7 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "enter\n"); spin_lock_irqsave(&priv->lock, flags); - memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); + memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config)); spin_unlock_irqrestore(&priv->lock, flags); iwl_reset_qos(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 79ea42531e28..a2ee95028c6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -277,7 +277,7 @@ int iwl_check_rxon_cmd(struct iwl_priv *priv); 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); +void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf); 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); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 961d53440034..e161f8d1766e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -502,7 +502,7 @@ union iwl_ht_rate_supp { #define CFG_HT_MPDU_DENSITY_4USEC (0x5) #define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC -struct iwl_ht_info { +struct iwl_ht_config { /* self configuration data */ bool is_ht; bool is_40mhz; @@ -1077,7 +1077,7 @@ struct iwl_priv { struct iwl_chain_noise_data chain_noise_data; __le16 sensitivity_tbl[HD_TABLE_SIZE]; - struct iwl_ht_info current_ht_config; + struct iwl_ht_config current_ht_config; u8 last_phy_res[100]; /* Rate scaling data */ -- cgit v1.2.3 From e307ddce394ee7bcec41fb74330ac89eafaea1d9 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:16 -0700 Subject: iwlwifi: show NVM version in debugfs Show version number along with dumping NVM data, the version information being removed from sysfs, add it back to debugfs to help debugging. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index a198bcf61022..037b75ca77f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -383,6 +383,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, int pos = 0, ofs = 0, buf_size = 0; const u8 *ptr; char *buf; + u16 eeprom_ver; size_t eeprom_len = priv->cfg->eeprom_size; buf_size = 4 * eeprom_len + 256; @@ -403,9 +404,11 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, IWL_ERR(priv, "Can not allocate Buffer\n"); return -ENOMEM; } - pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n", + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, " + "version: 0x%x\n", (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) - ? "OTP" : "EEPROM"); + ? "OTP" : "EEPROM", eeprom_ver); for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos, -- cgit v1.2.3 From 02bb1bea85e6570b4e64825026382556970b9296 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 11 Sep 2009 10:38:17 -0700 Subject: iwlwifi: clarify and clean up chain settings The chain settings we currently use in iwlwifi are rather confusing -- and we also go by the wrong settings entirely under certain circumstances. To clean it up, create a new variable in the current HT config -- single_chain_sufficient -- that tells us whether we need more than one chain. Calculate that based on the AP and operating mode (no IBSS HT implemented -- so no need for multiple chains, for station mode we use the AP's capabilities). Additionally, since APs always send disabled SM PS mode, keeping track of their sm_ps mode isn't very useful -- doubly not so for our _own_ RX config since that should depend on our, not the AP's, SM PS mode. Finally, document that our configuration of the number of RX chains used is currently wrong when in powersave (by adding a comment). All together this removes the two remaining items in struct iwl_ht_config that were done wrong there. For the future, the number of RX chains and some SM PS handshaking needs to be added to mac80211, which then needs to tell us, and the new variable current_ht_config.single_chain_sufficient should also be calculated by mac80211. Signed-off-by: Johannes Berg Acked-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 105 +++++++++++++++----------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 +- 2 files changed, 51 insertions(+), 57 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 9d01fde92cc6..2908bff49a3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -607,8 +607,7 @@ EXPORT_SYMBOL(iwlcore_free_geos); static bool is_single_rx_stream(struct iwl_priv *priv) { return !priv->current_ht_config.is_ht || - ((priv->current_ht_config.mcs.rx_mask[1] == 0) && - (priv->current_ht_config.mcs.rx_mask[2] == 0)); + priv->current_ht_config.single_chain_sufficient; } static u8 iwl_is_channel_extension(struct iwl_priv *priv, @@ -936,12 +935,8 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf) if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv); - IWL_DEBUG_ASSOC(priv, "supported HT rate 0x%X 0x%X 0x%X " - "rxon flags 0x%X operation mode :0x%X " + IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X " "extension channel offset 0x%x\n", - ht_conf->mcs.rx_mask[0], - ht_conf->mcs.rx_mask[1], - ht_conf->mcs.rx_mask[2], le32_to_cpu(rxon->flags), ht_conf->ht_protection, ht_conf->extension_chan_offset); return; @@ -960,12 +955,8 @@ EXPORT_SYMBOL(iwl_set_rxon_ht); */ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) { - bool is_single = is_single_rx_stream(priv); - bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); - /* # of Rx chains to use when expecting MIMO. */ - if (is_single || (!is_cam && (priv->current_ht_config.sm_ps == - WLAN_HT_CAP_SM_PS_STATIC))) + if (is_single_rx_stream(priv)) return IWL_NUM_RX_CHAINS_SINGLE; else return IWL_NUM_RX_CHAINS_MULTIPLE; @@ -973,27 +964,17 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) { - int idle_cnt; bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); + /* # Rx chains when idling and maybe trying to save power */ - switch (priv->current_ht_config.sm_ps) { - case WLAN_HT_CAP_SM_PS_STATIC: - case WLAN_HT_CAP_SM_PS_DYNAMIC: - idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : - IWL_NUM_IDLE_CHAINS_SINGLE; - break; - case WLAN_HT_CAP_SM_PS_DISABLED: - idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; - break; - case WLAN_HT_CAP_SM_PS_INVALID: - default: - IWL_ERR(priv, "invalid mimo ps mode %d\n", - priv->current_ht_config.sm_ps); - WARN_ON(1); - idle_cnt = -1; - break; - } - return idle_cnt; + + /* + * XXX: this is incorrect!! + * we always indicate to the AP that + * our SM PS mode is "disabled" + */ + + return is_cam ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; } /* up to 4 chains */ @@ -1493,8 +1474,6 @@ int iwl_init_drv(struct iwl_priv *priv) priv->iw_mode = NL80211_IFTYPE_STATION; - priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; - /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv); @@ -2226,10 +2205,9 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, EXPORT_SYMBOL(iwl_mac_conf_tx); static void iwl_ht_conf(struct iwl_priv *priv, - struct ieee80211_bss_conf *bss_conf) + struct ieee80211_bss_conf *bss_conf) { struct iwl_ht_config *ht_conf = &priv->current_ht_config; - struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta *sta; IWL_DEBUG_MAC80211(priv, "enter: \n"); @@ -2237,31 +2215,48 @@ static void iwl_ht_conf(struct iwl_priv *priv, if (!ht_conf->is_ht) return; - - /* - * It is totally wrong to base global information on something - * that is valid only when associated, alas, this driver works - * that way and I don't know how to fix it. - */ - - rcu_read_lock(); - sta = ieee80211_find_sta(priv->hw, priv->bssid); - if (!sta) { - rcu_read_unlock(); - return; - } - ht_cap = &sta->ht_cap; - - ht_conf->sm_ps = (u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS) >> 2); - - memcpy(&ht_conf->mcs, &ht_cap->mcs, 16); - ht_conf->ht_protection = bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; ht_conf->non_GF_STA_present = !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); - rcu_read_unlock(); + ht_conf->single_chain_sufficient = false; + + switch (priv->iw_mode) { + case NL80211_IFTYPE_STATION: + rcu_read_lock(); + sta = ieee80211_find_sta(priv->hw, priv->bssid); + if (sta) { + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; + int maxstreams; + + maxstreams = (ht_cap->mcs.tx_params & + IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) + >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; + maxstreams += 1; + + if ((ht_cap->mcs.rx_mask[1] == 0) && + (ht_cap->mcs.rx_mask[2] == 0)) + ht_conf->single_chain_sufficient = true; + if (maxstreams <= 1) + ht_conf->single_chain_sufficient = true; + } else { + /* + * If at all, this can only happen through a race + * when the AP disconnects us while we're still + * setting up the connection, in that case mac80211 + * will soon tell us about that. + */ + ht_conf->single_chain_sufficient = true; + } + rcu_read_unlock(); + break; + case NL80211_IFTYPE_ADHOC: + ht_conf->single_chain_sufficient = true; + break; + default: + break; + } IWL_DEBUG_MAC80211(priv, "leave\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e161f8d1766e..0c80692f934b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -506,8 +506,7 @@ struct iwl_ht_config { /* self configuration data */ bool is_ht; bool is_40mhz; - u8 sm_ps; - struct ieee80211_mcs_info mcs; + bool single_chain_sufficient; /* BSS related data */ u8 extension_chan_offset; u8 ht_protection; -- cgit v1.2.3 From 47eef9bd1079edbc3e6606309c733a2316ca5a72 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:44 -0700 Subject: iwlwifi: Use RTS/CTS as the preferred protection mechanism for 6000 series When 802.11g was introduced, we had RTS/CTS and CTS-to-Self protection mechanisms. In an HT Beacon, HT stations use the "Operating Mode" field in the HT Information Element to determine whether or not to use protection. The Operating Mode field has 4 possible settings: 0-3: Mode 0: If all stations in the BSS are 20/40 MHz HT capable, or if the BSS is 20/40 MHz capable, or if all stations in the BSS are 20 MHz HT stations in a 20 MHz BSS Mode 1: used if there are non-HT stations or APs using the primary or secondary channels Mode 2: if only HT stations are associated in the BSS and at least one 20 MHz HT station is associated. Mode 3: used if one or more non-HT stations are associated in the BSS. When in operating modes 1 or 3, and the Use_Protection field is 1 in the Beacon's ERP IE, all HT transmissions must be protected using RTS/CTS or CTS-to-Self. By default, CTS-to-self is the preferred protection mechanism for less overhead and higher throughput; but using the full RTS/CTS will better protect the inner exchange from interference, especially in highly-congested environment. For 6000 series WIFI NIC, RTS/CTS protection mechanism is the recommended choice for HT traffic based on the HW design. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 9 +++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 10 +++++++--- drivers/net/wireless/iwlwifi/iwl-core.h | 4 +++- 4 files changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 48b2b7d2170c..a9665ce1d658 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -259,6 +259,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ }; /* @@ -283,6 +284,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -304,6 +306,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -325,6 +328,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -346,6 +350,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ }; 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 18af37c964cb..469d56321d88 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -418,6 +418,15 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, else if (tid == IWL_AGG_ALL_TID) for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); + if (priv->cfg->use_rts_for_ht) { + /* + * switch to RTS/CTS if it is the prefer protection method + * for HT traffic + */ + IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n"); + priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN; + iwlcore_commit_rxon(priv); + } } static inline int get_num_of_ant_from_rate(u32 rate_n_flags) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index cdc07c477457..a3739628c1d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -115,9 +115,6 @@ int iwl_commit_rxon(struct iwl_priv *priv) /* always get timestamp with Rx frame */ priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; - /* allow CTS-to-self if possible. this is relevant only for - * 5000, but will not damage 4965 */ - priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; ret = iwl_check_rxon_cmd(priv); if (ret) { @@ -217,6 +214,13 @@ int iwl_commit_rxon(struct iwl_priv *priv) "Could not send WEP static key.\n"); } + /* + * allow CTS-to-self if possible for new association. + * this is relevant only for 5000 series and up, + * but will not damage 4965 + */ + priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; + /* Apply the new configuration * RXON assoc doesn't clear the station table in uCode, */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a2ee95028c6e..c7675c387140 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -216,6 +216,7 @@ struct iwl_mod_params { * @led_compensation: compensate on the led on/off time per HW according * to the deviation to achieve the desired led frequency. * The detail algorithm is described in iwl-led.c + * @use_rts_for_ht: use rts/cts protection for HT traffic * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -257,8 +258,9 @@ struct iwl_cfg { const u16 max_ll_items; const bool shadow_ram_support; const bool ht_greenfield_support; - const bool broken_powersave; u16 led_compensation; + const bool broken_powersave; + bool use_rts_for_ht; }; /*************************** -- cgit v1.2.3 From 01abfbb282482d01e2ac2e6b00e75b248bf517c8 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:45 -0700 Subject: iwlwifi: allow user change protection mechanism for HT Allow user to change protection mechanism for HT between RTS/CTS and CTS-to-self through sysfs: Show current protection mechanism for HT cat /sys/class/net/wlan0/device/rts_ht_protection Change protection mechanism for HT (only allowed while not-associated) CTS-to-self: echo 0 > /sys/class/net/wlan0/device/rts_ht_protection RTS/CTS: echo 1 > /sys/class/net/wlan0/device/rts_ht_protection Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a3739628c1d6..2a7cc4bdf3fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2798,6 +2798,40 @@ static ssize_t show_statistics(struct device *d, static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); +static ssize_t show_rts_ht_protection(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + return sprintf(buf, "%s\n", + priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self"); +} + +static ssize_t store_rts_ht_protection(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + IWL_INFO(priv, "Input is not in decimal form.\n"); + else { + if (!iwl_is_associated(priv)) + priv->cfg->use_rts_for_ht = val ? true : false; + else + IWL_ERR(priv, "Sta associated with AP - " + "Change protection mechanism is not allowed\n"); + ret = count; + } + return ret; +} + +static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO, + show_rts_ht_protection, store_rts_ht_protection); + /***************************************************************************** * @@ -2854,6 +2888,7 @@ static struct attribute *iwl_sysfs_entries[] = { &dev_attr_statistics.attr, &dev_attr_temperature.attr, &dev_attr_tx_power.attr, + &dev_attr_rts_ht_protection.attr, #ifdef CONFIG_IWLWIFI_DEBUG &dev_attr_debug_level.attr, #endif -- cgit v1.2.3 From 1f4b9665032c4a1d60efd9ceaad2781cae6c7e92 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:46 -0700 Subject: iwlwifi: EEPROM version for 1000 and 6000 series Update EEPROM version requirement for 1000 and 6000 series of NIC for EEPROM version verification. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-6000.c | 10 +++++----- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 6 ++++++ 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 1dd8db2f6f23..879b3753a3bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -155,7 +155,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .sku = IWL_SKU_G|IWL_SKU_N, .ops = &iwl1000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_1000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a9665ce1d658..0d2cbab1f7d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -248,7 +248,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, @@ -273,7 +273,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, @@ -295,7 +295,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, @@ -317,7 +317,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, @@ -339,7 +339,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 61794eb3d689..75fe02282998 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -256,6 +256,12 @@ struct iwl_eeprom_enhanced_txpwr { #define EEPROM_5050_TX_POWER_VERSION (4) #define EEPROM_5050_EEPROM_VERSION (0x21E) +/* 1000 Specific */ +#define EEPROM_1000_EEPROM_VERSION (0x15D) + +/* 60x0 Specific */ +#define EEPROM_6000_EEPROM_VERSION (0x434) + /* OTP */ /* lower blocks contain EEPROM image and calibration data */ #define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ -- cgit v1.2.3 From 4e30cb691b9ba62642cc1594ef08f7439deb5a02 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:47 -0700 Subject: iwlwifi: use S_IRUGO and S_IWUSR in module parameters Instead of hardcode module parameter's permissions, use pre-defined. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 15 ++++++++------- drivers/net/wireless/iwlwifi/iwl-5000.c | 11 ++++++----- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 11 ++++++----- 4 files changed, 22 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 2500ab2e1d91..b5111702856a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2361,21 +2361,22 @@ struct iwl_cfg iwl4965_agn_cfg = { /* Module firmware */ MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX)); -module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444); +module_param_named(antenna, iwl4965_mod_params.antenna, int, S_IRUGO); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); +module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, S_IRUGO); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); module_param_named( - disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444); + disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, S_IRUGO); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); -module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444); +module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, S_IRUGO); MODULE_PARM_DESC(queues_num, "number of hw queues."); /* 11n */ -module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, 0444); +module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, S_IRUGO); MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); -module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, int, 0444); +module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, + int, S_IRUGO); MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); -module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, 0444); +module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart4965, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c81fd4bc32b4..75fa55db330e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1752,14 +1752,15 @@ struct iwl_cfg iwl5150_agn_cfg = { MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); -module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); +module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, S_IRUGO); MODULE_PARM_DESC(swcrypto50, "using software crypto engine (default 0 [hardware])\n"); -module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); +module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, S_IRUGO); MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); -module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444); +module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, S_IRUGO); MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality"); -module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444); +module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, + int, S_IRUGO); MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series"); -module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444); +module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2a7cc4bdf3fd..cf2b481dca6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3322,9 +3322,9 @@ module_exit(iwl_exit); module_init(iwl_init); #ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug50, iwl_debug_level, uint, 0444); +module_param_named(debug50, iwl_debug_level, uint, S_IRUGO); MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)"); -module_param_named(debug, iwl_debug_level, uint, 0644); +module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c390dbd877e4..4a4af0f782f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4225,18 +4225,19 @@ static void __exit iwl3945_exit(void) MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX)); -module_param_named(antenna, iwl3945_mod_params.antenna, int, 0444); +module_param_named(antenna, iwl3945_mod_params.antenna, int, S_IRUGO); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444); +module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, S_IRUGO); MODULE_PARM_DESC(swcrypto, "using software crypto (default 1 [software])\n"); #ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug, iwl_debug_level, uint, 0644); +module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); #endif -module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444); +module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, + int, S_IRUGO); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); -module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444); +module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error"); module_exit(iwl3945_exit); -- cgit v1.2.3 From 95407aa4d48a8b3a2adf6a110853b544342913bd Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 17 Sep 2009 10:43:48 -0700 Subject: iwlwifi: clean up rs_tx_status Cut down on redundant code, reorganize structure, and add/improve comments. Should contain no functional changes. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 230 ++++++++++++++---------------- 1 file changed, 108 insertions(+), 122 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 469d56321d88..cd24763d5fde 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -820,6 +820,26 @@ out: return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green); } +/* + * Simple function to compare two rate scale table types + */ +static bool table_type_matches(struct iwl_scale_tbl_info *a, + struct iwl_scale_tbl_info *b) +{ + return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) && + (a->is_SGI == b->is_SGI); +} +/* + * Static function to get the expected throughput from an iwl_scale_tbl_info + * that wraps a NULL pointer check + */ +static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) +{ + if (tbl->expected_tpt) + return tbl->expected_tpt[rs_index]; + return 0; +} + /* * mac80211 sends us Tx status */ @@ -827,21 +847,19 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { - int status; - u8 retries; - int rs_index, mac_index, index = 0; + int legacy_success; + int retries; + int rs_index, mac_index, i; 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_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; - u8 active_index = 0; + struct iwl_scale_tbl_info *curr_tbl, *other_tbl; s32 tpt = 0; IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n"); @@ -855,25 +873,10 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - if (info->flags & IEEE80211_TX_STAT_AMPDU) - retries = 0; - else - retries = info->status.rates[0].count - 1; - - if (retries > 15) - retries = 15; if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) - goto out; - - table = &lq_sta->lq; - active_index = lq_sta->active_tbl; - - curr_tbl = &(lq_sta->lq_info[active_index]); - search_tbl = &(lq_sta->lq_info[(1 - active_index)]); - window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]); - search_win = (struct iwl_rate_scale_data *)&(search_tbl->win[0]); + return; /* * Ignore this Tx frame response if its initial rate doesn't match @@ -883,6 +886,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, * to check "search" mode, or a prior "search" mode after we've moved * to a new "search" mode (which might become the new "active" mode). */ + table = &lq_sta->lq; tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags); rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); if (priv->band == IEEE80211_BAND_5GHZ) @@ -901,7 +905,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, if (priv->band == IEEE80211_BAND_2GHZ) mac_index += IWL_FIRST_OFDM_RATE; } - + /* Here we actually compare this rate to the latest LQ command */ 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)) || @@ -911,124 +915,106 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, (!!(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 + /* + * Since rates mis-match, the last LQ command may have failed. + * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with + * ... driver. */ lq_sta->missed_rate_counter++; if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { lq_sta->missed_rate_counter = 0; iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } - goto out; + /* Regardless, ignore this status info for outdated rate */ + return; + } else + /* Rate did match, so reset the missed_rate_counter */ + lq_sta->missed_rate_counter = 0; + + /* Figure out if rate scale algorithm is in active or search table */ + if (table_type_matches(&tbl_type, + &(lq_sta->lq_info[lq_sta->active_tbl]))) { + curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); + } else if (table_type_matches(&tbl_type, + &lq_sta->lq_info[1 - lq_sta->active_tbl])) { + curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); + other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + } else { + IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n"); + return; } + window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]); - lq_sta->missed_rate_counter = 0; - /* Update frame history window with "failure" for each Tx retry. */ - while (retries) { - /* Look up the rate and other info used for each tx attempt. - * Each tx attempt steps one entry deeper in the rate table. */ - tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); - rs_get_tbl_info_from_mcs(tx_rate, priv->band, - &tbl_type, &rs_index); - - /* If type matches "search" table, - * add failure to "search" history */ - if ((tbl_type.lq_type == search_tbl->lq_type) && - (tbl_type.ant_type == search_tbl->ant_type) && - (tbl_type.is_SGI == search_tbl->is_SGI)) { - if (search_tbl->expected_tpt) - tpt = search_tbl->expected_tpt[rs_index]; - else - tpt = 0; - rs_collect_tx_data(search_win, rs_index, tpt, 1, 0); - - /* Else if type matches "current/active" table, - * add failure to "current/active" history */ - } else if ((tbl_type.lq_type == curr_tbl->lq_type) && - (tbl_type.ant_type == curr_tbl->ant_type) && - (tbl_type.is_SGI == curr_tbl->is_SGI)) { - if (curr_tbl->expected_tpt) - tpt = curr_tbl->expected_tpt[rs_index]; - else - tpt = 0; - rs_collect_tx_data(window, rs_index, tpt, 1, 0); + /* + * Updating the frame history depends on whether packets were + * aggregated. + * + * For aggregation, all packets were transmitted at the same rate, the + * first index into rate scale table. + */ + if (info->flags & IEEE80211_TX_STAT_AMPDU) { + tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, + &rs_index); + tpt = get_expected_tpt(curr_tbl, rs_index); + rs_collect_tx_data(window, rs_index, tpt, + info->status.ampdu_ack_len, + info->status.ampdu_ack_map); + + /* Update success/fail counts if not searching for new mode */ + if (lq_sta->stay_in_tbl) { + lq_sta->total_success += info->status.ampdu_ack_map; + lq_sta->total_failed += (info->status.ampdu_ack_len - + info->status.ampdu_ack_map); } - - /* If not searching for a new mode, increment failed counter - * ... this helps determine when to start searching again */ - if (lq_sta->stay_in_tbl) - lq_sta->total_failed++; - --retries; - index++; - - } - + } else { /* - * Find (by rate) the history window to update with final Tx attempt; - * if Tx was successful first try, use original rate, - * else look up the rate that was, finally, successful. + * For legacy, update frame history with for each Tx retry. */ - tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); - lq_sta->last_rate_n_flags = tx_rate; - rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); - - /* Update frame history window with "success" if Tx got ACKed ... */ - status = !!(info->flags & IEEE80211_TX_STAT_ACK); - - /* If type matches "search" table, - * add final tx status to "search" history */ - if ((tbl_type.lq_type == search_tbl->lq_type) && - (tbl_type.ant_type == search_tbl->ant_type) && - (tbl_type.is_SGI == search_tbl->is_SGI)) { - if (search_tbl->expected_tpt) - tpt = search_tbl->expected_tpt[rs_index]; - else - tpt = 0; - if (info->flags & IEEE80211_TX_STAT_AMPDU) - rs_collect_tx_data(search_win, rs_index, tpt, - info->status.ampdu_ack_len, - info->status.ampdu_ack_map); - else - rs_collect_tx_data(search_win, rs_index, tpt, - 1, status); - /* Else if type matches "current/active" table, - * add final tx status to "current/active" history */ - } else if ((tbl_type.lq_type == curr_tbl->lq_type) && - (tbl_type.ant_type == curr_tbl->ant_type) && - (tbl_type.is_SGI == curr_tbl->is_SGI)) { - if (curr_tbl->expected_tpt) - tpt = curr_tbl->expected_tpt[rs_index]; - else - tpt = 0; - if (info->flags & IEEE80211_TX_STAT_AMPDU) - rs_collect_tx_data(window, rs_index, tpt, - info->status.ampdu_ack_len, - info->status.ampdu_ack_map); - else - rs_collect_tx_data(window, rs_index, tpt, - 1, status); - } + retries = info->status.rates[0].count - 1; + /* HW doesn't send more than 15 retries */ + retries = min(retries, 15); + + /* The last transmission may have been successful */ + legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); + /* Collect data for each rate used during failed TX attempts */ + for (i = 0; i <= retries; ++i) { + tx_rate = le32_to_cpu(table->rs_table[i].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, + &tbl_type, &rs_index); + /* + * Only collect stats if retried rate is in the same RS + * table as active/search. + */ + if (table_type_matches(&tbl_type, curr_tbl)) + tpt = get_expected_tpt(curr_tbl, rs_index); + else if (table_type_matches(&tbl_type, other_tbl)) + tpt = get_expected_tpt(other_tbl, rs_index); + else + continue; - /* If not searching for new mode, increment success/failed counter - * ... these help determine when to start searching again */ - if (lq_sta->stay_in_tbl) { - if (info->flags & IEEE80211_TX_STAT_AMPDU) { - lq_sta->total_success += info->status.ampdu_ack_map; - lq_sta->total_failed += - (info->status.ampdu_ack_len - info->status.ampdu_ack_map); - } else { - if (status) - lq_sta->total_success++; + /* Constants mean 1 transmission, 0 successes */ + if (i < retries) + rs_collect_tx_data(window, rs_index, tpt, 1, + 0); else - lq_sta->total_failed++; + rs_collect_tx_data(window, rs_index, tpt, 1, + legacy_success); + } + + /* Update success/fail counts if not searching for new mode */ + if (lq_sta->stay_in_tbl) { + lq_sta->total_success += legacy_success; + lq_sta->total_failed += retries + (1 - legacy_success); } } + /* The last TX rate is cached in lq_sta; it's set in if/else above */ + lq_sta->last_rate_n_flags = tx_rate; /* See if there's a better rate or modulation mode to try. */ if (sta && sta->supp_rates[sband->band]) rs_rate_scale_perform(priv, skb, sta, lq_sta); -out: - return; } /* -- cgit v1.2.3 From 91a55ae60168847c3c8ab348f10d517407052b71 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 17 Sep 2009 10:43:49 -0700 Subject: iwlwifi: do not clear TX info flags when receiving BlockAckResponse OR-in AMPDU flags rather than assigning them. This lets the TX status for aggregated packets be processed by rs_tx_status. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index c18907544701..ad69479376a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1400,7 +1400,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]); memset(&info->status, 0, sizeof(info->status)); - info->flags = IEEE80211_TX_STAT_ACK; + info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_AMPDU; info->status.ampdu_ack_map = successes; info->status.ampdu_ack_len = agg->frame_count; -- cgit v1.2.3 From e3949d62861b3fdef19e80080d670aa1153a23c4 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 17 Sep 2009 10:43:50 -0700 Subject: iwlwifi: add aggregation tables to the rate scaling algorithm Current rate scale algorithm fluctuates between different MIMO modes fairly rapidly, causing widely varying performance. These fluctuations occur because in the rate_scale tables for expected throughput the values are not very different for different modes. However, when aggregation is turned on and MAC overhead is reduced, the expected throughput for different MIMO modes grows and different modes have vastly different performance. Add expected throughput tables for this case. We also need to keep track of aggregation status per-station, so we add the "is_agg" field to struct lq_sta. Also includes cleanup of comments and variable names in/around the affected code. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 223 +++++++++++++++--------------- 1 file changed, 115 insertions(+), 108 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index cd24763d5fde..e6c35e07f41b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -171,6 +171,8 @@ struct iwl_lq_sta { int last_txrate_idx; /* last tx rate_n_flags */ u32 last_rate_n_flags; + /* packets destined for this STA are aggregated */ + u8 is_agg; }; static void rs_rate_scale_perform(struct iwl_priv *priv, @@ -190,84 +192,78 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, {} #endif -/* - * Expected throughput metrics for following rates: - * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits - * "G" is the only table that supports CCK (the first 4 rates). +/** + * The following tables contain the expected throughput metrics for all rates + * + * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits + * + * where invalid entries are zeros. + * + * CCK rates are only valid in legacy table and will only be used in G + * (2.4 GHz) band. */ -static s32 expected_tpt_A[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 -}; - -static s32 expected_tpt_G[IWL_RATE_COUNT] = { - 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186 -}; - -static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202 -}; - -static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211 -}; - -static s32 expected_tpt_mimo2_20MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251 -}; - -static s32 expected_tpt_mimo2_20MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257 +static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { + 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0 }; -static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257 +static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 42, 0, 76, 102, 124, 158, 183, 193, 202}, /* Norm */ + {0, 0, 0, 0, 46, 0, 82, 110, 132, 167, 192, 202, 210}, /* SGI */ + {0, 0, 0, 0, 48, 0, 93, 135, 176, 251, 319, 351, 381}, /* AGG */ + {0, 0, 0, 0, 53, 0, 102, 149, 193, 275, 348, 381, 413}, /* AGG+SGI */ }; -static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264 +static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */ + {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */ + {0, 0, 0, 0, 96, 0, 182, 259, 328, 451, 553, 598, 640}, /* AGG */ + {0, 0, 0, 0, 106, 0, 199, 282, 357, 487, 593, 640, 683}, /* AGG+SGI */ }; -static s32 expected_tpt_mimo2_40MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289 +static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250}, /* Norm */ + {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256}, /* SGI */ + {0, 0, 0, 0, 92, 0, 175, 250, 317, 436, 534, 578, 619}, /* AGG */ + {0, 0, 0, 0, 102, 0, 192, 273, 344, 470, 573, 619, 660}, /* AGG+SGI*/ }; -static s32 expected_tpt_mimo2_40MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 +static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */ + {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */ + {0, 0, 0, 0, 180, 0, 327, 446, 545, 708, 828, 878, 922}, /* AGG */ + {0, 0, 0, 0, 197, 0, 355, 481, 584, 752, 872, 922, 966}, /* AGG+SGI */ }; -/* Expected throughput metric MIMO3 */ -static s32 expected_tpt_mimo3_20MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 99, 99, 153, 186, 208, 239, 256, 263, 268 +static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */ + {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */ + {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */ + {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */ }; -static s32 expected_tpt_mimo3_20MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 106, 106, 162, 194, 215, 246, 262, 268, 273 -}; - -static s32 expected_tpt_mimo3_40MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 152, 152, 211, 239, 255, 279, 290, 294, 297 -}; - -static s32 expected_tpt_mimo3_40MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 160, 160, 219, 245, 261, 284, 294, 297, 300 +static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */ + {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */ + {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */ + {0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */ }; /* mbps, mcs */ const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { - {"1", ""}, - {"2", ""}, - {"5.5", ""}, - {"11", ""}, - {"6", "BPSK 1/2"}, - {"9", "BPSK 1/2"}, - {"12", "QPSK 1/2"}, - {"18", "QPSK 3/4"}, - {"24", "16QAM 1/2"}, - {"36", "16QAM 3/4"}, - {"48", "64QAM 2/3"}, - {"54", "64QAM 3/4"}, - {"60", "64QAM 5/6"} + { "1", "BPSK DSSS"}, + { "2", "QPSK DSSS"}, + {"5.5", "BPSK CCK"}, + { "11", "QPSK CCK"}, + { "6", "BPSK 1/2"}, + { "9", "BPSK 1/2"}, + { "12", "QPSK 1/2"}, + { "18", "QPSK 3/4"}, + { "24", "16QAM 1/2"}, + { "36", "16QAM 3/4"}, + { "48", "64QAM 2/3"}, + { "54", "64QAM 3/4"}, + { "60", "64QAM 5/6"}, }; #define MCS_INDEX_PER_STREAM (8) @@ -444,7 +440,7 @@ static inline int get_num_of_ant_from_rate(u32 rate_n_flags) * packets. */ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, - int scale_index, s32 tpt, int retries, + int scale_index, s32 tpt, int attempts, int successes) { struct iwl_rate_scale_data *window = NULL; @@ -454,7 +450,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) return -EINVAL; - /* Select data for current tx bit rate */ + /* Select window for current tx bit rate */ window = &(windows[scale_index]); /* @@ -465,7 +461,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, * subtract "1" from the success counter (this is the main reason * we keep these bitmaps!). */ - while (retries > 0) { + while (attempts > 0) { if (window->counter >= IWL_RATE_MAX_WINDOW) { /* remove earliest */ @@ -480,17 +476,17 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, /* Increment frames-attempted counter */ window->counter++; - /* Shift bitmap by one frame (throw away oldest history), - * OR in "1", and increment "success" if this - * frame was successful. */ + /* Shift bitmap by one frame to throw away oldest history */ window->data <<= 1; + + /* Mark the most recent #successes attempts as successful */ if (successes > 0) { window->success_counter++; window->data |= 0x1; successes--; } - retries--; + attempts--; } /* Calculate current success ratio, avoid divide-by-0! */ @@ -868,12 +864,11 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, info->flags & IEEE80211_TX_CTL_NO_ACK) return; - /* This packet was aggregated but doesn't carry rate scale info */ + /* This packet was aggregated but doesn't carry status info */ if ((info->flags & IEEE80211_TX_CTL_AMPDU) && !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) return; @@ -1052,43 +1047,45 @@ static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy, static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl) { + /* Used to choose among HT tables */ + s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; + + /* Check for invalid LQ type */ + if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) { + tbl->expected_tpt = expected_tpt_legacy; + return; + } + + /* Legacy rates have only one table */ if (is_legacy(tbl->lq_type)) { - if (!is_a_band(tbl->lq_type)) - tbl->expected_tpt = expected_tpt_G; - else - tbl->expected_tpt = expected_tpt_A; - } else if (is_siso(tbl->lq_type)) { - if (tbl->is_ht40 && !lq_sta->is_dup) - if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_siso40MHzSGI; - else - tbl->expected_tpt = expected_tpt_siso40MHz; - else if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_siso20MHzSGI; - else - tbl->expected_tpt = expected_tpt_siso20MHz; - } else if (is_mimo2(tbl->lq_type)) { - if (tbl->is_ht40 && !lq_sta->is_dup) - if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI; - else - tbl->expected_tpt = expected_tpt_mimo2_40MHz; - else if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo2_20MHzSGI; - else - tbl->expected_tpt = expected_tpt_mimo2_20MHz; - } else if (is_mimo3(tbl->lq_type)) { - if (tbl->is_ht40 && !lq_sta->is_dup) - if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI; - else - tbl->expected_tpt = expected_tpt_mimo3_40MHz; - else if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo3_20MHzSGI; - else - tbl->expected_tpt = expected_tpt_mimo3_20MHz; - } else - tbl->expected_tpt = expected_tpt_G; + tbl->expected_tpt = expected_tpt_legacy; + return; + } + + /* Choose among many HT tables depending on number of streams + * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation + * status */ + if (is_siso(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup)) + ht_tbl_pointer = expected_tpt_siso20MHz; + else if (is_siso(tbl->lq_type)) + ht_tbl_pointer = expected_tpt_siso40MHz; + else if (is_mimo2(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup)) + ht_tbl_pointer = expected_tpt_mimo2_20MHz; + else if (is_mimo2(tbl->lq_type)) + ht_tbl_pointer = expected_tpt_mimo2_40MHz; + else if (is_mimo3(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup)) + ht_tbl_pointer = expected_tpt_mimo3_20MHz; + else /* if (is_mimo3(tbl->lq_type)) <-- must be true */ + ht_tbl_pointer = expected_tpt_mimo3_40MHz; + + if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */ + tbl->expected_tpt = ht_tbl_pointer[0]; + else if (tbl->is_SGI && !lq_sta->is_agg) /* SGI */ + tbl->expected_tpt = ht_tbl_pointer[1]; + else if (!tbl->is_SGI && lq_sta->is_agg) /* AGG */ + tbl->expected_tpt = ht_tbl_pointer[2]; + else /* AGG+SGI */ + tbl->expected_tpt = ht_tbl_pointer[3]; } /* @@ -2063,6 +2060,14 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; tid = rs_tl_add_packet(lq_sta, hdr); + if ((tid != MAX_TID_COUNT) && (lq_sta->tx_agg_tid_en & (1 << tid))) { + tid_data = &priv->stations[lq_sta->lq.sta_id].tid[tid]; + if (tid_data->agg.state == IWL_AGG_OFF) + lq_sta->is_agg = 0; + else + lq_sta->is_agg = 1; + } else + lq_sta->is_agg = 0; /* * Select rate-scale / modulation-mode table to work with in @@ -2163,10 +2168,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, goto out; } - /* Else we have enough samples; calculate estimate of * actual average throughput */ + /* Sanity-check TPT calculations */ BUG_ON(window->average_tpt != ((window->success_ratio * tbl->expected_tpt[index] + 64) / 128)); @@ -2676,6 +2681,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, 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; + lq_sta->is_agg = 0; rs_initialize_lq(priv, conf, sta, lq_sta); } @@ -2928,8 +2934,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); desc += sprintf(buff+desc, " %s", (tbl->is_ht40) ? "40MHz" : "20MHz"); - desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "", - (lq_sta->is_green) ? "GF enabled" : ""); + desc += sprintf(buff+desc, " %s %s %s\n", (tbl->is_SGI) ? "SGI" : "", + (lq_sta->is_green) ? "GF enabled" : "", + (lq_sta->is_agg) ? "AGG on" : ""); } desc += sprintf(buff+desc, "last tx rate=0x%X\n", lq_sta->last_rate_n_flags); -- cgit v1.2.3 From 2f748deceee10bac563df0e859830cc628d1a841 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:51 -0700 Subject: iwlwifi: send cmd to uCode to configure valid tx antenna In order for uCode to select the valid antennas for transmit, driver need to configure the allowed tx antennas through host command. The TX_ANT_CONFIGURATION_CMD should be used for 5000 series and up Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 19 +++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-commands.h | 12 +++++++++++- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 75fa55db330e..68d97f50fd00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1450,6 +1450,24 @@ int iwl5000_calc_rssi(struct iwl_priv *priv, return max_rssi - agc - IWL49_RSSI_OFFSET; } +static int iwl5000_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) +{ + struct iwl_tx_ant_config_cmd tx_ant_cmd = { + .valid = cpu_to_le32(valid_tx_ant), + }; + + if (IWL_UCODE_API(priv->ucode_ver) > 1) { + IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant); + return iwl_send_cmd_pdu(priv, TX_ANT_CONFIGURATION_CMD, + sizeof(struct iwl_tx_ant_config_cmd), + &tx_ant_cmd); + } else { + IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n"); + return -EOPNOTSUPP; + } +} + + #define IWL5000_UCODE_GET(item) \ static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\ u32 api_ver) \ @@ -1492,6 +1510,7 @@ struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, .set_rxon_chain = iwl_set_rxon_chain, + .set_tx_ant = iwl5000_send_tx_ant_config, }; struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index cf2b481dca6d..5505878dcaf7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1762,6 +1762,10 @@ static void iwl_alive_start(struct iwl_priv *priv) priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + /* Configure Tx antenna selection based on H/W config */ + if (priv->cfg->ops->hcmd->set_tx_ant) + priv->cfg->ops->hcmd->set_tx_ant(priv, priv->cfg->valid_tx_ant); + if (iwl_is_associated(priv)) { struct iwl_rxon_cmd *active_rxon = (struct iwl_rxon_cmd *)&priv->active_rxon; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 2c5c88fc38f5..e5f40f35dc3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -148,7 +148,7 @@ enum { QUIET_NOTIFICATION = 0x96, /* not used */ REPLY_TX_PWR_TABLE_CMD = 0x97, REPLY_TX_POWER_DBM_CMD_V1 = 0x98, /* old version of API */ - TX_ANT_CONFIGURATION_CMD = 0x98, /* not used */ + TX_ANT_CONFIGURATION_CMD = 0x98, MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ /* Bluetooth device coexistence config command */ @@ -411,6 +411,16 @@ struct iwl5000_tx_power_dbm_cmd { u8 reserved; } __attribute__ ((packed)); +/** + * Command TX_ANT_CONFIGURATION_CMD = 0x98 + * This command is used to configure valid Tx antenna. + * By default uCode concludes the valid antenna according to the radio flavor. + * This command enables the driver to override/modify this conclusion. + */ +struct iwl_tx_ant_config_cmd { + __le32 valid; +} __attribute__ ((packed)); + /****************************************************************************** * (0a) * Alive and Error Commands & Responses: diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index c7675c387140..f094cd9de443 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -89,6 +89,7 @@ struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); int (*commit_rxon)(struct iwl_priv *priv); void (*set_rxon_chain)(struct iwl_priv *priv); + int (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant); }; struct iwl_hcmd_utils_ops { -- cgit v1.2.3 From 4bd0914fa2a09d655c54fb0355aed7f9182b2187 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:52 -0700 Subject: iwlwifi: update PCI Subsystem ID for 1000 series Update PCI Subsystem ID for 1000 series based on HW SKU. Adding new SKU for "BG" only devices. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 20 ++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 14 ++++++++++++-- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 879b3753a3bd..3b3e6bc74ba9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -167,3 +167,23 @@ struct iwl_cfg iwl1000_bgn_cfg = { .led_compensation = 51, }; +struct iwl_cfg iwl1000_bg_cfg = { + .name = "1000 Series BG", + .fw_name_pre = IWL1000_FW_PRE, + .ucode_api_max = IWL1000_UCODE_API_MAX, + .ucode_api_min = IWL1000_UCODE_API_MIN, + .sku = IWL_SKU_G, + .ops = &iwl1000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_1000_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, + .led_compensation = 51, +}; + diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 5505878dcaf7..0c95b0ec5fb3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3270,8 +3270,18 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x0088, PCI_ANY_ID, iwl6050_3agn_cfg)}, {IWL_PCI_DEVICE(0x0089, PCI_ANY_ID, iwl6050_2agn_cfg)}, /* 1000 Series WiFi */ - {IWL_PCI_DEVICE(0x0083, PCI_ANY_ID, iwl1000_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0084, PCI_ANY_ID, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1305, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1225, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1325, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0084, 0x1215, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0084, 0x1315, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1206, iwl1000_bg_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1306, iwl1000_bg_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1226, iwl1000_bg_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1326, iwl1000_bg_cfg)}, + {IWL_PCI_DEVICE(0x0084, 0x1216, iwl1000_bg_cfg)}, + {IWL_PCI_DEVICE(0x0084, 0x1316, iwl1000_bg_cfg)}, #endif /* CONFIG_IWL5000 */ {0} diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0c80692f934b..cca4c6a4b060 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -62,6 +62,7 @@ extern struct iwl_cfg iwl6000_3agn_cfg; extern struct iwl_cfg iwl6050_2agn_cfg; extern struct iwl_cfg iwl6050_3agn_cfg; extern struct iwl_cfg iwl1000_bgn_cfg; +extern struct iwl_cfg iwl1000_bg_cfg; struct iwl_tx_queue; -- cgit v1.2.3 From 5953a62e7df064a5d7ba7e790d590f27c65ddf4c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:53 -0700 Subject: iwlwifi: update PCI Subsystem ID for 6000 series Update PCI Subsystem ID for 60x0 series based on HW SKU. Adding new SKU for "ABG" and "BG" only devices. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 105 ++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 43 +++++++++---- drivers/net/wireless/iwlwifi/iwl-dev.h | 5 ++ 3 files changed, 142 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 0d2cbab1f7d2..01a1f81cba2a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -262,6 +262,48 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ }; +struct iwl_cfg iwl6000h_2abg_cfg = { + .name = "6000 Series 2x2 ABG", + .fw_name_pre = IWL6000_FW_PRE, + .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_min = IWL6000_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G, + .ops = &iwl6000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_AB, + .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, + .led_compensation = 51, +}; + +struct iwl_cfg iwl6000h_2bg_cfg = { + .name = "6000 Series 2x2 BG", + .fw_name_pre = IWL6000_FW_PRE, + .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_min = IWL6000_UCODE_API_MIN, + .sku = IWL_SKU_G, + .ops = &iwl6000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_AB, + .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, + .led_compensation = 51, +}; + /* * "i": Internal configuration, use internal Power Amplifier */ @@ -287,6 +329,48 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ }; +struct iwl_cfg iwl6000i_2abg_cfg = { + .name = "6000 Series 2x2 ABG", + .fw_name_pre = IWL6000_FW_PRE, + .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_min = IWL6000_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G, + .ops = &iwl6000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_BC, + .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, + .led_compensation = 51, +}; + +struct iwl_cfg iwl6000i_2bg_cfg = { + .name = "6000 Series 2x2 BG", + .fw_name_pre = IWL6000_FW_PRE, + .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_min = IWL6000_UCODE_API_MIN, + .sku = IWL_SKU_G, + .ops = &iwl6000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_BC, + .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, + .led_compensation = 51, +}; + struct iwl_cfg iwl6050_2agn_cfg = { .name = "6050 Series 2x2 AGN", .fw_name_pre = IWL6050_FW_PRE, @@ -309,6 +393,27 @@ struct iwl_cfg iwl6050_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ }; +struct iwl_cfg iwl6050_2abg_cfg = { + .name = "6050 Series 2x2 ABG", + .fw_name_pre = IWL6050_FW_PRE, + .ucode_api_max = IWL6050_UCODE_API_MAX, + .ucode_api_min = IWL6050_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G, + .ops = &iwl6000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_AB, + .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, + .led_compensation = 51, +}; + struct iwl_cfg iwl6000_3agn_cfg = { .name = "6000 Series 3x3 AGN", .fw_name_pre = IWL6000_FW_PRE, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0c95b0ec5fb3..26c66b4ffd60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3258,17 +3258,38 @@ static struct pci_device_id iwl_hw_card_ids[] = { /* 5150 Wifi/WiMax */ {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)}, {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, -/* 6000/6050 Series */ - {IWL_PCI_DEVICE(0x008D, PCI_ANY_ID, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x008E, PCI_ANY_ID, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x422B, PCI_ANY_ID, iwl6000_3agn_cfg)}, - {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000i_2agn_cfg)}, - {IWL_PCI_DEVICE(0x4238, PCI_ANY_ID, iwl6000_3agn_cfg)}, - {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000i_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0086, PCI_ANY_ID, iwl6050_3agn_cfg)}, - {IWL_PCI_DEVICE(0x0087, PCI_ANY_ID, iwl6050_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0088, PCI_ANY_ID, iwl6050_3agn_cfg)}, - {IWL_PCI_DEVICE(0x0089, PCI_ANY_ID, iwl6050_2agn_cfg)}, + +/* 6x00 Series */ + {IWL_PCI_DEVICE(0x008D, 0x1301, iwl6000h_2agn_cfg)}, + {IWL_PCI_DEVICE(0x008D, 0x1321, iwl6000h_2agn_cfg)}, + {IWL_PCI_DEVICE(0x008D, 0x1326, iwl6000h_2abg_cfg)}, + {IWL_PCI_DEVICE(0x008D, 0x1306, iwl6000h_2abg_cfg)}, + {IWL_PCI_DEVICE(0x008D, 0x1307, iwl6000h_2bg_cfg)}, + {IWL_PCI_DEVICE(0x008E, 0x1311, iwl6000h_2agn_cfg)}, + {IWL_PCI_DEVICE(0x008E, 0x1316, iwl6000h_2abg_cfg)}, + + {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)}, + {IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)}, + {IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)}, + {IWL_PCI_DEVICE(0x422C, 0x1306, iwl6000i_2abg_cfg)}, + {IWL_PCI_DEVICE(0x422C, 0x1307, iwl6000i_2bg_cfg)}, + {IWL_PCI_DEVICE(0x422C, 0x1321, iwl6000i_2agn_cfg)}, + {IWL_PCI_DEVICE(0x422C, 0x1326, iwl6000i_2abg_cfg)}, + {IWL_PCI_DEVICE(0x4238, 0x1111, iwl6000_3agn_cfg)}, + {IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)}, + {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)}, + +/* 6x50 WiFi/WiMax Series */ + {IWL_PCI_DEVICE(0x0086, 0x1101, iwl6050_3agn_cfg)}, + {IWL_PCI_DEVICE(0x0086, 0x1121, iwl6050_3agn_cfg)}, + {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)}, + {IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)}, + {IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)}, + {IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)}, + {IWL_PCI_DEVICE(0x0088, 0x1111, iwl6050_3agn_cfg)}, + {IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)}, + {IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)}, + /* 1000 Series WiFi */ {IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)}, {IWL_PCI_DEVICE(0x0083, 0x1305, iwl1000_bgn_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cca4c6a4b060..3ea97be7f6b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -57,9 +57,14 @@ extern struct iwl_cfg iwl5100_bg_cfg; extern struct iwl_cfg iwl5100_abg_cfg; extern struct iwl_cfg iwl5150_agn_cfg; extern struct iwl_cfg iwl6000h_2agn_cfg; +extern struct iwl_cfg iwl6000h_2abg_cfg; +extern struct iwl_cfg iwl6000h_2bg_cfg; extern struct iwl_cfg iwl6000i_2agn_cfg; +extern struct iwl_cfg iwl6000i_2abg_cfg; +extern struct iwl_cfg iwl6000i_2bg_cfg; extern struct iwl_cfg iwl6000_3agn_cfg; extern struct iwl_cfg iwl6050_2agn_cfg; +extern struct iwl_cfg iwl6050_2abg_cfg; extern struct iwl_cfg iwl6050_3agn_cfg; extern struct iwl_cfg iwl1000_bgn_cfg; extern struct iwl_cfg iwl1000_bg_cfg; -- cgit v1.2.3 From 02f5dac08364d01a8b2c8e298b529b97f356b3f5 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:54 -0700 Subject: iwlwifi: add LED mode to support different LED behavior Today's implementation allow LED to blink based on the traffic condition. We introduce an additional LED mode that reflects the RF state. The supported LED modes after this are: IWL_LED_BLINK (current/default) - blink rate based on current Tx/Rx traffic IWL_LED_RF_STATE (new) - LED OFF: No power/RF disabled, the LED is emitting no light LED ON: Powered/RF enabled, the LED is emitting light in a stable non-flashing state. In order to provide the flexibility to support different LED behavior per user/system preference we add "led_mode" iwlcore module parameter. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-led.c | 9 ++++++++- drivers/net/wireless/iwlwifi/iwl-led.h | 12 ++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index f547233c5b79..685ba9d6f082 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -42,6 +42,12 @@ #include "iwl-core.h" #include "iwl-io.h" +/* default: IWL_LED_BLINK(0) using blinking index table */ +static int led_mode; +module_param(led_mode, int, S_IRUGO); +MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), " + "(default 0)\n"); + #ifdef CONFIG_IWLWIFI_DEBUG static const char *led_type_str[] = { __stringify(IWL_LED_TRG_TX), @@ -199,7 +205,8 @@ static int iwl_led_off_reg(struct iwl_priv *priv, int led_id) static int iwl_led_associate(struct iwl_priv *priv, int led_id) { IWL_DEBUG_LED(priv, "Associated\n"); - priv->allow_blinking = 1; + if (led_mode == IWL_LED_BLINK) + priv->allow_blinking = 1; return iwl_led_on_reg(priv, led_id); } static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index ef9b174c37ff..dd76b266c633 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -47,6 +47,18 @@ enum led_type { IWL_LED_TRG_RADIO, IWL_LED_TRG_MAX, }; + +/* + * LED mode + * IWL_LED_BLINK: adjust led blink rate based on blink table + * IWL_LED_RF_STATE: turn LED on/off based on RF state + * LED ON = RF ON + * LED OFF = RF OFF + */ +enum iwl_led_mode { + IWL_LED_BLINK, + IWL_LED_RF_STATE, +}; #endif #ifdef CONFIG_IWLWIFI_LEDS -- cgit v1.2.3 From 9bddbab36d736c181678e07515aaa63045bdcea7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Sep 2009 14:24:24 -0700 Subject: iwlwifi: fix a typo We never have four chains, but let's fix the typo while we noticed it. You count 0, 1, 2, 3, not 0, 1, 2, 4 :) Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2908bff49a3b..5ff0f66f8aa1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -984,7 +984,7 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap) res = (chain_bitmap & BIT(0)) >> 0; res += (chain_bitmap & BIT(1)) >> 1; res += (chain_bitmap & BIT(2)) >> 2; - res += (chain_bitmap & BIT(4)) >> 4; + res += (chain_bitmap & BIT(3)) >> 3; return res; } -- cgit v1.2.3 From 2b396a120922062a0ffd2648be3ed7e72ff83620 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Sep 2009 14:24:25 -0700 Subject: iwlwifi: default to using all chains When instructing the microcode to use just a single chain when we have power saving enabled, we should also tell the AP that we are doing SM powersave. However, using a single chain doesn't actually have any power saving advantage while idle -- measurements show that the power consumption is no different when using one vs. two or three chains. Therefore, always instruct the microcode to use all chains. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5ff0f66f8aa1..e97b104ba1d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -948,8 +948,13 @@ EXPORT_SYMBOL(iwl_set_rxon_ht); #define IWL_NUM_IDLE_CHAINS_DUAL 2 #define IWL_NUM_IDLE_CHAINS_SINGLE 1 -/* Determine how many receiver/antenna chains to use. - * More provides better reception via diversity. Fewer saves power. +/* + * Determine how many receiver/antenna chains to use. + * + * More provides better reception via diversity. Fewer saves power + * at the expense of throughput, but only when not in powersave to + * start with. + * * MIMO (dual stream) requires at least 2, but works better with 3. * This does not determine *which* chains to use, just how many. */ @@ -962,19 +967,18 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) return IWL_NUM_RX_CHAINS_MULTIPLE; } +/* + * When we are in power saving, there's no difference between + * using multiple chains or just a single chain, but due to the + * lack of SM PS we lose a lot of throughput if we use just a + * single chain. + * + * Therefore, use the active count here (which will use multiple + * chains unless connected to a legacy AP). + */ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) { - bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); - - /* # Rx chains when idling and maybe trying to save power */ - - /* - * XXX: this is incorrect!! - * we always indicate to the AP that - * our SM PS mode is "disabled" - */ - - return is_cam ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; + return active_cnt; } /* up to 4 chains */ -- cgit v1.2.3 From d8c07e7a84950b5fdef424c6dabe6bed3a9ffa19 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 25 Sep 2009 14:24:26 -0700 Subject: iwlwifi: Chain Noise Calibration for 6000 series Adding support of Chain Noise Calibration for 6000 series NICs. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 + drivers/net/wireless/iwlwifi/iwl-4965.c | 6 ++- drivers/net/wireless/iwlwifi/iwl-5000.c | 15 ++++++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 19 ++++++---- drivers/net/wireless/iwlwifi/iwl-calib.c | 64 ++++++++++++++++++++++---------- drivers/net/wireless/iwlwifi/iwl-core.h | 5 ++- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 +- 7 files changed, 80 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 3b3e6bc74ba9..9dfd4c407efb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -165,6 +165,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .shadow_ram_support = false, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl1000_bg_cfg = { @@ -185,5 +186,6 @@ struct iwl_cfg iwl1000_bg_cfg = { .shadow_ram_support = false, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b5111702856a..4e492c154f88 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -495,14 +495,15 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv) static void iwl4965_gain_computation(struct iwl_priv *priv, u32 *average_noise, u16 min_average_noise_antenna_i, - u32 min_average_noise) + u32 min_average_noise, + u8 default_chain) { int i, ret; struct iwl_chain_noise_data *data = &priv->chain_noise_data; data->delta_gain_code[min_average_noise_antenna_i] = 0; - for (i = 0; i < NUM_RX_CHAINS; i++) { + for (i = default_chain; i < NUM_RX_CHAINS; i++) { s32 delta_g = 0; if (!(data->disconn_array[i]) && @@ -2356,6 +2357,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .ht_greenfield_support = false, .broken_powersave = true, .led_compensation = 61, + .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 68d97f50fd00..660fd51d190b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -301,14 +301,17 @@ u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv) static void iwl5000_gain_computation(struct iwl_priv *priv, u32 average_noise[NUM_RX_CHAINS], u16 min_average_noise_antenna_i, - u32 min_average_noise) + u32 min_average_noise, + u8 default_chain) { int i; s32 delta_g; struct iwl_chain_noise_data *data = &priv->chain_noise_data; - /* Find Gain Code for the antennas B and C */ - for (i = 1; i < NUM_RX_CHAINS; i++) { + /* + * Find Gain Code for the chains based on "default chain" + */ + for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) { if ((data->disconn_array[i])) { data->delta_gain_code[i] = 0; continue; @@ -1676,6 +1679,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl5100_bg_cfg = { @@ -1694,6 +1698,7 @@ struct iwl_cfg iwl5100_bg_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -1712,6 +1717,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -1730,6 +1736,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1748,6 +1755,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1766,6 +1774,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; 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 01a1f81cba2a..ad5d77c96494 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -222,18 +222,11 @@ static struct iwl_lib_ops iwl6000_lib = { }, }; -static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = { - .get_hcmd_size = iwl5000_get_hcmd_size, - .build_addsta_hcmd = iwl5000_build_addsta_hcmd, - .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag, - .calc_rssi = iwl5000_calc_rssi, -}; - static struct iwl_ops iwl6000_ops = { .ucode = &iwl5000_ucode, .lib = &iwl6000_lib, .hcmd = &iwl5000_hcmd, - .utils = &iwl6000_hcmd_utils, + .utils = &iwl5000_hcmd_utils, }; @@ -260,6 +253,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6000h_2abg_cfg = { @@ -281,6 +275,7 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6000h_2bg_cfg = { @@ -302,6 +297,7 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; /* @@ -327,6 +323,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -348,6 +345,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -369,6 +367,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -391,6 +390,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -412,6 +412,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -434,6 +435,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -456,6 +458,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 6e73317c3b40..69a80d7c2e44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -643,6 +643,15 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_sensitivity_calibration); +static inline u8 find_first_chain(u8 mask) +{ + if (mask & ANT_A) + return CHAIN_A; + if (mask & ANT_B) + return CHAIN_B; + return CHAIN_C; +} + /* * Accumulate 20 beacons of signal and noise statistics for each of * 3 receivers/antennas/rx-chains, then figure out: @@ -675,14 +684,17 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, u8 num_tx_chains; unsigned long flags; struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general); + u8 first_chain; if (priv->disable_chain_noise_cal) return; data = &(priv->chain_noise_data); - /* Accumulate just the first 20 beacons after the first association, - * then we're done forever. */ + /* + * Accumulate just the first "chain_noise_num_beacons" after + * the first association, then we're done forever. + */ if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) { if (data->state == IWL_CHAIN_NOISE_ALIVE) IWL_DEBUG_CALIB(priv, "Wait for noise calib reset\n"); @@ -710,7 +722,10 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, return; } - /* Accumulate beacon statistics values across 20 beacons */ + /* + * Accumulate beacon statistics values across + * "chain_noise_num_beacons" + */ chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) & @@ -741,16 +756,19 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, IWL_DEBUG_CALIB(priv, "chain_noise: a %d b %d c %d\n", chain_noise_a, chain_noise_b, chain_noise_c); - /* If this is the 20th beacon, determine: + /* If this is the "chain_noise_num_beacons", determine: * 1) Disconnected antennas (using signal strengths) * 2) Differential gain (using silence noise) to balance receivers */ - if (data->beacon_count != CAL_NUM_OF_BEACONS) + if (data->beacon_count != priv->cfg->chain_noise_num_beacons) return; /* Analyze signal for disconnected antenna */ - average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS; - average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS; - average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS; + average_sig[0] = + (data->chain_signal_a) / priv->cfg->chain_noise_num_beacons; + average_sig[1] = + (data->chain_signal_b) / priv->cfg->chain_noise_num_beacons; + average_sig[2] = + (data->chain_signal_c) / priv->cfg->chain_noise_num_beacons; if (average_sig[0] >= average_sig[1]) { max_average_sig = average_sig[0]; @@ -803,13 +821,17 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, /* there is a Tx antenna connected */ break; if (num_tx_chains == priv->hw_params.tx_chains_num && - data->disconn_array[i]) { - /* This is the last TX antenna and is also - * disconnected connect it anyway */ - data->disconn_array[i] = 0; - active_chains |= ant_msk; - IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - " - "declare %d as connected\n", i); + data->disconn_array[i]) { + /* + * If all chains are disconnected + * connect the first valid tx chain + */ + first_chain = + find_first_chain(priv->cfg->valid_tx_ant); + data->disconn_array[first_chain] = 0; + active_chains |= BIT(first_chain); + IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - declare %d as connected\n", + first_chain); break; } } @@ -820,9 +842,12 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, active_chains); /* Analyze noise for rx balance */ - average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); - average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); - average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS); + average_noise[0] = + ((data->chain_noise_a) / priv->cfg->chain_noise_num_beacons); + average_noise[1] = + ((data->chain_noise_b) / priv->cfg->chain_noise_num_beacons); + average_noise[2] = + ((data->chain_noise_c) / priv->cfg->chain_noise_num_beacons); for (i = 0; i < NUM_RX_CHAINS; i++) { if (!(data->disconn_array[i]) && @@ -843,7 +868,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, if (priv->cfg->ops->utils->gain_computation) priv->cfg->ops->utils->gain_computation(priv, average_noise, - min_average_noise_antenna_i, min_average_noise); + min_average_noise_antenna_i, min_average_noise, + find_first_chain(priv->cfg->valid_rx_ant)); /* Some power changes may have been made during the calibration. * Update and commit the RXON diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f094cd9de443..b66bf7b4b0a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -98,7 +98,8 @@ struct iwl_hcmd_utils_ops { void (*gain_computation)(struct iwl_priv *priv, u32 *average_noise, u16 min_average_noise_antennat_i, - u32 min_average_noise); + u32 min_average_noise, + u8 default_chain); void (*chain_noise_reset)(struct iwl_priv *priv); void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info, __le32 *tx_flags); @@ -218,6 +219,7 @@ struct iwl_mod_params { * to the deviation to achieve the desired led frequency. * The detail algorithm is described in iwl-led.c * @use_rts_for_ht: use rts/cts protection for HT traffic + * @chain_noise_num_beacons: number of beacons used to compute chain noise * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -262,6 +264,7 @@ struct iwl_cfg { u16 led_compensation; const bool broken_powersave; bool use_rts_for_ht; + int chain_noise_num_beacons; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 3ea97be7f6b2..ad99ce7824c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -743,7 +743,8 @@ struct iwl_dma_ptr { /* Sensitivity and chain noise calibration */ #define INITIALIZATION_VALUE 0xFFFF -#define CAL_NUM_OF_BEACONS 20 +#define IWL4965_CAL_NUM_BEACONS 20 +#define IWL_CAL_NUM_BEACONS 16 #define MAXIMUM_ALLOWED_PATHLOSS 15 #define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3 -- cgit v1.2.3 From 78f5fb7fc6c2c668a12fd6892c18baa20e4ffd27 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Sep 2009 14:24:27 -0700 Subject: iwlwifi: support idle for 6000 series hw Using powersave while idle saves a lot of power, but we've had problems with this on some cards (5150 has been reported to be problematic). However, on the new 6000 series we're seeing no problems, so for now let that hardware benefit from idle mode, we can look at the problems with other hardware one by one and then enable those once we figure out the problems. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-power.c | 3 +++ 4 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index ad5d77c96494..6f4ee27e07c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -254,6 +254,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6000h_2abg_cfg = { @@ -276,6 +277,7 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6000h_2bg_cfg = { @@ -298,6 +300,7 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; /* @@ -324,6 +327,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -346,6 +350,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -368,6 +373,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -391,6 +397,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -413,6 +420,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -436,6 +444,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -459,6 +468,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e97b104ba1d5..1cf2e04fe3f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2650,7 +2650,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) iwl_set_rate(priv); } - if (changed & IEEE80211_CONF_CHANGE_PS) { + if (changed & (IEEE80211_CONF_CHANGE_PS | + IEEE80211_CONF_CHANGE_IDLE)) { ret = iwl_power_update_mode(priv, false); if (ret) IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b66bf7b4b0a4..744f0cac6859 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -265,6 +265,7 @@ struct iwl_cfg { const bool broken_powersave; bool use_rts_for_ht; int chain_noise_num_beacons; + const bool supports_idle; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 60be976afff8..e50d77bd7aad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -294,6 +294,9 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) if (priv->cfg->broken_powersave) iwl_power_sleep_cam_cmd(priv, &cmd); + else if (priv->cfg->supports_idle && + priv->hw->conf.flags & IEEE80211_CONF_IDLE) + iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20); else if (tt->state >= IWL_TI_1) iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper); else if (!enabled) -- cgit v1.2.3 From 9554b34ad5817f424253aab265d0e2a54207f810 Mon Sep 17 00:00:00 2001 From: Huaxu Wan Date: Fri, 25 Sep 2009 14:24:28 -0700 Subject: iwlwifi: add module firmware info for 1000 series The module firmware information of 1000 series is missing from iwlagn. Signed-off-by: Huaxu Wan Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 9dfd4c407efb..af91dbab255a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -189,3 +189,4 @@ struct iwl_cfg iwl1000_bg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; +MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); -- cgit v1.2.3 From c099752ae06784fcd9cd393cbf3dfbc6b54f4569 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 18 Sep 2009 18:20:03 +0200 Subject: iwlwifi: drop lib80211 dependency Ever since Johannes' "iwlwifi: improve scan support" iwlwifi no longer needs any of lib80211's functions or definitions. This patch updates iwlwifi's Kconfig _selections_ and removes all left lib80211.h inclusions from the source files. Signed-off-by: Christian Lamparter Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 1 - drivers/net/wireless/iwlwifi/iwl-scan.c | 1 - drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 99310c033253..eb62c20e8019 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -1,7 +1,6 @@ config IWLWIFI tristate "Intel Wireless Wifi" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL - select LIB80211 select FW_LOADER select MAC80211_LEDS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 4f3a108fa990..41f9a0621250 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -27,7 +27,6 @@ *****************************************************************************/ #include #include -#include #include #include "iwl-eeprom.h" diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4a4af0f782f0..3575e7fbadc7 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -41,7 +41,6 @@ #include #include -#include #include #include -- cgit v1.2.3 From 7812b16730ccebce71a3b2228ac08dd4f8b39469 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 2 Oct 2009 13:43:58 -0700 Subject: iwlwifi: reliable entering of critical temperature state When uCode detects critical temperature it should send "card state notification" interrupt to driver and then shut itself down to prevent overheating. There is a race condition where uCode shuts down before it can deliver the interrupt to driver. Additional method provided here for driver to enter CT_KILL state based on temperature reading. How it works: Method 1: If driver receive "card state notification" interrupt from uCode; it enters "CT_KILL" state immediately Method 2: If the last temperature report by Card reach Critical temperature, driver will send "statistic notification" request to uCode to verify the temperature reading, if driver can not get reply from uCode within 300ms, driver will enter CT_KILL state automatically. Method 3: If the last temperature report by Card did not reach Critical temperature, but uCode already shut down due to critical temperature. All the host commands send to uCode will not get process by uCode; when command queue reach the limit, driver will check the last reported temperature reading, if it is within pre-defined margin, enter "CT_KILL" state immediately. In this case, when uCode ready to exit from "CT_KILL" state, driver need to restart the adapter in order to reset all the queues and resume normal operation. One additional issue being address here, when system is in CT_KILL state, both tx and rx already stopped, but driver still can send host command to uCode, it will flood the command queue since card was not responding; adding STATUS_CT_KILL flag to reject enqueue host commands to uCode if it is in CT_KILL state, when uCode is ready to come out of CT_KILL, driver will clear the STATUS_CT_KILL bit and allow enqueue the host commands to uCode to recover from CT_KILL state. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.h | 6 ++ drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 + drivers/net/wireless/iwlwifi/iwl-power.c | 146 +++++++++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-power.h | 3 + drivers/net/wireless/iwlwifi/iwl-tx.c | 10 +- 5 files changed, 135 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 744f0cac6859..3bd0e59bb5a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -580,6 +580,7 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 #define STATUS_RF_KILL_HW 3 +#define STATUS_CT_KILL 4 #define STATUS_INIT 5 #define STATUS_ALIVE 6 #define STATUS_READY 7 @@ -624,6 +625,11 @@ static inline int iwl_is_rfkill(struct iwl_priv *priv) return iwl_is_rfkill_hw(priv); } +static inline int iwl_is_ctkill(struct iwl_priv *priv) +{ + return test_bit(STATUS_CT_KILL, &priv->status); +} + static inline int iwl_is_ready_rf(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 037b75ca77f1..fa6371d171c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -535,6 +535,8 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, test_bit(STATUS_INT_ENABLED, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", test_bit(STATUS_RF_KILL_HW, &priv->status)); + pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n", + test_bit(STATUS_CT_KILL, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n", test_bit(STATUS_INIT, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index e50d77bd7aad..9c6b14952061 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -165,26 +165,26 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, *============================================================================= * Condition Nxt State Condition Nxt State Condition Nxt State *----------------------------------------------------------------------------- - * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A - * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 - * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 + * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A + * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0 + * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1 * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 *============================================================================= */ static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = { {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104}, - {IWL_TI_1, 105, CT_KILL_THRESHOLD}, - {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} + {IWL_TI_1, 105, CT_KILL_THRESHOLD - 1}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX} }; static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = { {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95}, - {IWL_TI_2, 110, CT_KILL_THRESHOLD}, - {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} + {IWL_TI_2, 110, CT_KILL_THRESHOLD - 1}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX} }; static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = { {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100}, - {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}, - {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX} }; static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = { {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD}, @@ -351,6 +351,23 @@ bool iwl_ht_enabled(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_ht_enabled); +bool iwl_within_ct_kill_margin(struct iwl_priv *priv) +{ + s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ + bool within_margin = false; + + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) + temp = KELVIN_TO_CELSIUS(priv->temperature); + + if (!priv->thermal_throttle.advanced_tt) + within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >= + CT_KILL_THRESHOLD_LEGACY) ? true : false; + else + within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >= + CT_KILL_THRESHOLD) ? true : false; + return within_margin; +} + enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; @@ -375,6 +392,7 @@ enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv) } #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ +#define CT_KILL_WAITING_DURATION (300) /* 300ms duration */ /* * toggle the bit to wake up uCode and check the temperature @@ -412,6 +430,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 */ + IWL_DEBUG_POWER(priv, "schedule ct_kill exit timer\n"); mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + CT_KILL_EXIT_DURATION * HZ); } @@ -435,6 +454,33 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, } } +static void iwl_tt_ready_for_ct_kill(unsigned long data) +{ + struct iwl_priv *priv = (struct iwl_priv *)data; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + /* temperature timer expired, ready to go into CT_KILL state */ + if (tt->state != IWL_TI_CT_KILL) { + IWL_DEBUG_POWER(priv, "entering CT_KILL state when temperature timer expired\n"); + tt->state = IWL_TI_CT_KILL; + set_bit(STATUS_CT_KILL, &priv->status); + iwl_perform_ct_kill_task(priv, true); + } +} + +static void iwl_prepare_ct_kill_task(struct iwl_priv *priv) +{ + IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n"); + /* make request to retrieve statistics information */ + iwl_send_statistics_request(priv, 0); + /* Reschedule the ct_kill wait timer */ + mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm, + jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION)); +} + #define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY) #define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100) #define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90) @@ -448,7 +494,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, * Throttle early enough to lower the power consumption before * drastic steps are needed */ -static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) +static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; enum iwl_tt_state old_state; @@ -477,6 +523,8 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) #ifdef CONFIG_IWLWIFI_DEBUG tt->tt_previous_temp = temp; #endif + /* stop ct_kill_waiting_tm timer */ + del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm); if (tt->state != old_state) { switch (tt->state) { case IWL_TI_0: @@ -497,17 +545,28 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) break; } mutex_lock(&priv->mutex); - if (iwl_power_update_mode(priv, true)) { + if (old_state == IWL_TI_CT_KILL) + clear_bit(STATUS_CT_KILL, &priv->status); + if (tt->state != IWL_TI_CT_KILL && + iwl_power_update_mode(priv, true)) { /* TT state not updated * try again during next temperature read */ + if (old_state == IWL_TI_CT_KILL) + set_bit(STATUS_CT_KILL, &priv->status); tt->state = old_state; IWL_ERR(priv, "Cannot update power mode, " "TT state not updated\n"); } else { - if (tt->state == IWL_TI_CT_KILL) - iwl_perform_ct_kill_task(priv, true); - else if (old_state == IWL_TI_CT_KILL && + if (tt->state == IWL_TI_CT_KILL) { + if (force) { + set_bit(STATUS_CT_KILL, &priv->status); + iwl_perform_ct_kill_task(priv, true); + } else { + iwl_prepare_ct_kill_task(priv); + tt->state = old_state; + } + } else if (old_state == IWL_TI_CT_KILL && tt->state != IWL_TI_CT_KILL) iwl_perform_ct_kill_task(priv, false); IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", @@ -534,13 +593,13 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) *============================================================================= * Condition Nxt State Condition Nxt State Condition Nxt State *----------------------------------------------------------------------------- - * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A - * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 - * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 + * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A + * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0 + * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1 * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 *============================================================================= */ -static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) +static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; int i; @@ -585,6 +644,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) break; } } + /* stop ct_kill_waiting_tm timer */ + del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm); if (changed) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -616,12 +677,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) iwl_set_rxon_ht(priv, &priv->current_ht_config); } mutex_lock(&priv->mutex); - if (iwl_power_update_mode(priv, true)) { + if (old_state == IWL_TI_CT_KILL) + clear_bit(STATUS_CT_KILL, &priv->status); + if (tt->state != IWL_TI_CT_KILL && + iwl_power_update_mode(priv, true)) { /* TT state not updated * try again during next temperature read */ IWL_ERR(priv, "Cannot update power mode, " "TT state not updated\n"); + if (old_state == IWL_TI_CT_KILL) + set_bit(STATUS_CT_KILL, &priv->status); tt->state = old_state; } else { IWL_DEBUG_POWER(priv, @@ -629,9 +695,15 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) tt->state); if (old_state != IWL_TI_CT_KILL && tt->state == IWL_TI_CT_KILL) { - IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n"); - iwl_perform_ct_kill_task(priv, true); - + if (force) { + IWL_DEBUG_POWER(priv, + "Enter IWL_TI_CT_KILL\n"); + set_bit(STATUS_CT_KILL, &priv->status); + iwl_perform_ct_kill_task(priv, true); + } else { + iwl_prepare_ct_kill_task(priv); + tt->state = old_state; + } } else if (old_state == IWL_TI_CT_KILL && tt->state != IWL_TI_CT_KILL) { IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n"); @@ -668,10 +740,11 @@ static void iwl_bg_ct_enter(struct work_struct *work) "- ucode going to sleep!\n"); if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, - IWL_MINIMAL_POWER_THRESHOLD); + IWL_MINIMAL_POWER_THRESHOLD, + true); else iwl_advance_tt_handler(priv, - CT_KILL_THRESHOLD + 1); + CT_KILL_THRESHOLD + 1, true); } } @@ -698,11 +771,18 @@ static void iwl_bg_ct_exit(struct work_struct *work) IWL_ERR(priv, "Device temperature below critical" "- ucode awake!\n"); + /* + * exit from CT_KILL state + * reset the current temperature reading + */ + priv->temperature = 0; if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, - IWL_REDUCED_PERFORMANCE_THRESHOLD_2); + IWL_REDUCED_PERFORMANCE_THRESHOLD_2, + true); else - iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); + iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD, + true); } } @@ -738,9 +818,9 @@ static void iwl_bg_tt_work(struct work_struct *work) temp = KELVIN_TO_CELSIUS(priv->temperature); if (!priv->thermal_throttle.advanced_tt) - iwl_legacy_tt_handler(priv, temp); + iwl_legacy_tt_handler(priv, temp, false); else - iwl_advance_tt_handler(priv, temp); + iwl_advance_tt_handler(priv, temp, false); } void iwl_tt_handler(struct iwl_priv *priv) @@ -771,8 +851,12 @@ void iwl_tt_initialize(struct iwl_priv *priv) tt->state = IWL_TI_0; 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; - + priv->thermal_throttle.ct_kill_exit_tm.function = + iwl_tt_check_exit_ct_kill; + init_timer(&priv->thermal_throttle.ct_kill_waiting_tm); + priv->thermal_throttle.ct_kill_waiting_tm.data = (unsigned long)priv; + priv->thermal_throttle.ct_kill_waiting_tm.function = + iwl_tt_ready_for_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); @@ -829,6 +913,8 @@ void iwl_tt_exit(struct iwl_priv *priv) /* stop ct_kill_exit_tm timer if activated */ del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); + /* stop ct_kill_waiting_tm timer if activated */ + del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm); cancel_work_sync(&priv->tt_work); cancel_work_sync(&priv->ct_enter); cancel_work_sync(&priv->ct_exit); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index df6f6a49712b..310c32e8f698 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -33,6 +33,7 @@ #define IWL_ABSOLUTE_ZERO 0 #define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 +#define IWL_TT_CT_KILL_MARGIN 3 enum iwl_antenna_ok { IWL_ANT_OK_NONE, @@ -110,6 +111,7 @@ struct iwl_tt_mgmt { struct iwl_tt_restriction *restriction; struct iwl_tt_trans *transaction; struct timer_list ct_kill_exit_tm; + struct timer_list ct_kill_waiting_tm; }; enum iwl_power_level { @@ -129,6 +131,7 @@ struct iwl_power_mgr { int iwl_power_update_mode(struct iwl_priv *priv, bool force); bool iwl_ht_enabled(struct iwl_priv *priv); +bool iwl_within_ct_kill_margin(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); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index ad69479376a6..2ba9725beff9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -969,13 +969,19 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && !(cmd->flags & CMD_SIZE_HUGE)); - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n"); + if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { + IWL_DEBUG_INFO(priv, "Not sending command - RF/CT KILL\n"); return -EIO; } if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERR(priv, "No space for Tx\n"); + if (iwl_within_ct_kill_margin(priv)) + iwl_tt_enter_ct_kill(priv); + else { + IWL_ERR(priv, "Restarting adapter due to queue full\n"); + queue_work(priv->workqueue, &priv->restart); + } return -ENOSPC; } -- cgit v1.2.3 From 72f0ebd9e0af0cb642b5f8955380c5043c5c83b4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 2 Oct 2009 13:43:59 -0700 Subject: iwlwifi: change valid EEPROM version for 1000 series In order to support different type of 1000 series NICs we release to customers before the production release, iwlwifi driver need to support all the NICs has EEPROM version greater than 0x15c. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 75fe02282998..643142f913b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -257,7 +257,7 @@ struct iwl_eeprom_enhanced_txpwr { #define EEPROM_5050_EEPROM_VERSION (0x21E) /* 1000 Specific */ -#define EEPROM_1000_EEPROM_VERSION (0x15D) +#define EEPROM_1000_EEPROM_VERSION (0x15C) /* 60x0 Specific */ #define EEPROM_6000_EEPROM_VERSION (0x434) -- cgit v1.2.3 From 39d5e0ce0f2ab9a4bb88e22a9f07ba3943e3646d Mon Sep 17 00:00:00 2001 From: Huaxu Wan Date: Fri, 2 Oct 2009 13:44:00 -0700 Subject: iwlwifi: clear the translate table area Driver should clear the translate table area after receiving "Alive" response from uCode. This patch corrects a mistake when doing this. Signed-off-by: Huaxu Wan Signed-off-by: Guo Chaohong Acked-by: Ben M Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-5000.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 4e492c154f88..0921e454185b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -663,7 +663,8 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) iwl_write_targ_mem(priv, a, 0); for (; a < priv->scd_base_addr + IWL49_SCD_TRANSLATE_TBL_OFFSET; a += 4) iwl_write_targ_mem(priv, a, 0); - for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4) + for (; a < priv->scd_base_addr + + IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4) iwl_write_targ_mem(priv, a, 0); /* Tel 4965 where to find Tx byte count tables */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 660fd51d190b..01d53ebb96ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -748,7 +748,8 @@ int iwl5000_alive_notify(struct iwl_priv *priv) for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET; a += 4) iwl_write_targ_mem(priv, a, 0); - for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4) + for (; a < priv->scd_base_addr + + IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4) iwl_write_targ_mem(priv, a, 0); iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR, -- cgit v1.2.3 From 4d80d7210bb5a36a18978d1305b44375ecb857d9 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 2 Oct 2009 13:44:01 -0700 Subject: iwlwifi: set default aggregation frame count limit to 31 Multiple MPDUs can be aggregated, transmitted, and finally acknowledged together using a single BA frame. Block ACK (BA) contains bitmap size of 64*16 bits so the maximum frame count is 64. The default value of aggregation frame count suggested by uCode is 31 to achieve best performance. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index e6c35e07f41b..a07be29cc5e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2800,7 +2800,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, repeat_rate--; } - lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX; + lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; lq_cmd->agg_params.agg_time_limit = cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); -- cgit v1.2.3 From be1a71a128ed91372d4ad8d54d8fd972a1a356eb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 2 Oct 2009 13:44:02 -0700 Subject: iwlwifi: device tracing In order to have an easier way to debug issues, create trace events (using the ftrace framework) that will allow us to follow exactly what the driver is doing with the device. The text format isn't all that useful, but the binary format can also be obtained easily via debugfs and then analysed on the fly or offline with debugging tools. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 18 +++ drivers/net/wireless/iwlwifi/Makefile | 7 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++ drivers/net/wireless/iwlwifi/iwl-devtrace.c | 13 ++ drivers/net/wireless/iwlwifi/iwl-devtrace.h | 178 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 2 + drivers/net/wireless/iwlwifi/iwl-io.h | 16 ++- drivers/net/wireless/iwlwifi/iwl-tx.c | 14 ++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 8 +- 9 files changed, 256 insertions(+), 8 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-devtrace.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-devtrace.h (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index eb62c20e8019..48d8f2cf566c 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -49,6 +49,24 @@ config IWLWIFI_DEBUGFS ---help--- Enable creation of debugfs files for the iwlwifi drivers. +config IWLWIFI_DEVICE_TRACING + bool "iwlwifi device access tracing" + depends on IWLWIFI + depends on EVENT_TRACING + help + Say Y here to trace all commands, including TX frames and IO + accesses, sent to the device. If you say yes, iwlwifi will + register with the ftrace framework for event tracing and dump + all this information to the ringbuffer, you may need to + increase the ringbuffer size. See the ftrace documentation + for more information. + + When tracing is not enabled, this option still has some + (though rather small) overhead. + + If unsure, say Y so we can help you better when problems + occur. + config IWLAGN tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)" depends on IWLWIFI diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 1d4e0a226fd4..3f31d866054b 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -5,7 +5,11 @@ iwlcore-objs += iwl-scan.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o +iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o +CFLAGS_iwl-devtrace.o := -I$(src) + +# AGN obj-$(CONFIG_IWLAGN) += iwlagn.o iwlagn-objs := iwl-agn.o iwl-agn-rs.o @@ -14,7 +18,6 @@ iwlagn-$(CONFIG_IWL5000) += iwl-5000.o iwlagn-$(CONFIG_IWL5000) += iwl-6000.o iwlagn-$(CONFIG_IWL5000) += iwl-1000.o +# 3945 obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o - - diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 26c66b4ffd60..4fb50d0eb536 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -791,6 +791,9 @@ void iwl_rx_handle(struct iwl_priv *priv) PCI_DMA_FROMDEVICE); pkt = (struct iwl_rx_packet *)rxb->skb->data; + trace_iwlwifi_dev_rx(priv, pkt, + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); + /* Reclaim a command buffer only if this packet is a response * to a (driver-originated) command. * If the packet (e.g. Rx frame) originated from uCode, @@ -1610,6 +1613,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); + trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line, + blink1, blink2, ilink1, ilink2); + IWL_ERR(priv, "Desc Time " "data1 data2 line\n"); IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n", @@ -1658,12 +1664,14 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, ptr += sizeof(u32); if (mode == 0) { /* data, ev */ + trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); } else { data = iwl_read_targ_mem(priv, ptr); ptr += sizeof(u32); IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", time, data, ev); + trace_iwlwifi_dev_ucode_event(priv, time, data, ev); } } } diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c new file mode 100644 index 000000000000..4ef5acaa556d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -0,0 +1,13 @@ +#include + +/* sparse doesn't like tracepoint macros */ +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "iwl-devtrace.h" + +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error); +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h new file mode 100644 index 000000000000..8c7159208da1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -0,0 +1,178 @@ +#if !defined(__IWLWIFI_DEVICE_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define __IWLWIFI_DEVICE_TRACE + +#include +#include "iwl-dev.h" + +#if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__) +#undef TRACE_EVENT +#define TRACE_EVENT(name, proto, ...) \ +static inline void trace_ ## name(proto) {} +#endif + +#define PRIV_ENTRY __field(struct iwl_priv *, priv) +#define PRIV_ASSIGN __entry->priv = priv + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM iwlwifi + +TRACE_EVENT(iwlwifi_dev_ioread32, + TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val), + TP_ARGS(priv, offs, val), + TP_STRUCT__entry( + PRIV_ENTRY + __field(u32, offs) + __field(u32, val) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->offs = offs; + __entry->val = val; + ), + TP_printk("[%p] read io[%#x] = %#x", __entry->priv, __entry->offs, __entry->val) +); + +TRACE_EVENT(iwlwifi_dev_iowrite32, + TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val), + TP_ARGS(priv, offs, val), + TP_STRUCT__entry( + PRIV_ENTRY + __field(u32, offs) + __field(u32, val) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->offs = offs; + __entry->val = val; + ), + TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val) +); + +TRACE_EVENT(iwlwifi_dev_hcmd, + TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags), + TP_ARGS(priv, hcmd, len, flags), + TP_STRUCT__entry( + PRIV_ENTRY + __dynamic_array(u8, hcmd, len) + __field(u32, flags) + ), + TP_fast_assign( + PRIV_ASSIGN; + memcpy(__get_dynamic_array(hcmd), hcmd, len); + __entry->flags = flags; + ), + TP_printk("[%p] hcmd %#.2x (%ssync)", + __entry->priv, ((u8 *)__get_dynamic_array(hcmd))[0], + __entry->flags & CMD_ASYNC ? "a" : "") +); + +TRACE_EVENT(iwlwifi_dev_rx, + TP_PROTO(struct iwl_priv *priv, void *rxbuf, size_t len), + TP_ARGS(priv, rxbuf, len), + TP_STRUCT__entry( + PRIV_ENTRY + __dynamic_array(u8, rxbuf, len) + ), + TP_fast_assign( + PRIV_ASSIGN; + memcpy(__get_dynamic_array(rxbuf), rxbuf, len); + ), + TP_printk("[%p] RX cmd %#.2x", + __entry->priv, ((u8 *)__get_dynamic_array(rxbuf))[4]) +); + +TRACE_EVENT(iwlwifi_dev_tx, + TP_PROTO(struct iwl_priv *priv, void *tfd, size_t tfdlen, + void *buf0, size_t buf0_len, + void *buf1, size_t buf1_len), + TP_ARGS(priv, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len), + TP_STRUCT__entry( + PRIV_ENTRY + + __field(size_t, framelen) + __dynamic_array(u8, tfd, tfdlen) + + /* + * Do not insert between or below these items, + * we want to keep the frame together (except + * for the possible padding). + */ + __dynamic_array(u8, buf0, buf0_len) + __dynamic_array(u8, buf1, buf1_len) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->framelen = buf0_len + buf1_len; + memcpy(__get_dynamic_array(tfd), tfd, tfdlen); + memcpy(__get_dynamic_array(buf0), buf0, buf0_len); + memcpy(__get_dynamic_array(buf1), buf1, buf0_len); + ), + TP_printk("[%p] TX %.2x (%zu bytes)", + __entry->priv, + ((u8 *)__get_dynamic_array(buf0))[0], + __entry->framelen) +); + +TRACE_EVENT(iwlwifi_dev_ucode_error, + TP_PROTO(struct iwl_priv *priv, u32 desc, u32 time, + u32 data1, u32 data2, u32 line, u32 blink1, + u32 blink2, u32 ilink1, u32 ilink2), + TP_ARGS(priv, desc, time, data1, data2, line, + blink1, blink2, ilink1, ilink2), + TP_STRUCT__entry( + PRIV_ENTRY + __field(u32, desc) + __field(u32, time) + __field(u32, data1) + __field(u32, data2) + __field(u32, line) + __field(u32, blink1) + __field(u32, blink2) + __field(u32, ilink1) + __field(u32, ilink2) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->desc = desc; + __entry->time = time; + __entry->data1 = data1; + __entry->data2 = data2; + __entry->line = line; + __entry->blink1 = blink1; + __entry->blink2 = blink2; + __entry->ilink1 = ilink1; + __entry->ilink2 = ilink2; + ), + TP_printk("[%p] #%02d %010u data 0x%08X 0x%08X line %u, " + "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X", + __entry->priv, __entry->desc, __entry->time, __entry->data1, + __entry->data2, __entry->line, __entry->blink1, + __entry->blink2, __entry->ilink1, __entry->ilink2) +); + +TRACE_EVENT(iwlwifi_dev_ucode_event, + TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev), + TP_ARGS(priv, time, data, ev), + TP_STRUCT__entry( + PRIV_ENTRY + + __field(u32, time) + __field(u32, data) + __field(u32, ev) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->time = time; + __entry->data = data; + __entry->ev = ev; + ), + TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u", + __entry->priv, __entry->time, __entry->data, __entry->ev) +); +#endif /* __IWLWIFI_DEVICE_TRACE */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE iwl-devtrace +#include diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 643142f913b6..fee6f0c7503e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -63,6 +63,8 @@ #ifndef __iwl_eeprom_h__ #define __iwl_eeprom_h__ +#include + struct iwl_priv; /* diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index d30cb0275d19..0a078b082833 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -32,6 +32,7 @@ #include #include "iwl-debug.h" +#include "iwl-devtrace.h" /* * IO, register, and NIC memory access functions @@ -61,7 +62,12 @@ * */ -#define _iwl_write32(priv, ofs, val) iowrite32((val), (priv)->hw_base + (ofs)) +static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) +{ + trace_iwlwifi_dev_iowrite32(priv, ofs, val); + iowrite32(val, priv->hw_base + ofs); +} + #ifdef CONFIG_IWLWIFI_DEBUG static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, u32 ofs, u32 val) @@ -75,7 +81,13 @@ static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, #define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val) #endif -#define _iwl_read32(priv, ofs) ioread32((priv)->hw_base + (ofs)) +static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs) +{ + u32 val = ioread32(priv->hw_base + ofs); + trace_iwlwifi_dev_ioread32(priv, ofs, val); + return val; +} + #ifdef CONFIG_IWLWIFI_DEBUG static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) { diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 2ba9725beff9..c832ba085dba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -709,7 +709,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) dma_addr_t phys_addr; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; - u16 len, len_org; + u16 len, len_org, firstlen, secondlen; u16 seq_number = 0; __le16 fc; u8 hdr_len; @@ -842,7 +842,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) sizeof(struct iwl_cmd_header) + hdr_len; len_org = len; - len = (len + 3) & ~3; + firstlen = len = (len + 3) & ~3; if (len_org != len) len_org = 1; @@ -876,7 +876,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ - len = skb->len - hdr_len; + secondlen = len = skb->len - hdr_len; if (len) { phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, len, PCI_DMA_TODEVICE); @@ -910,6 +910,12 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys, len, PCI_DMA_BIDIRECTIONAL); + trace_iwlwifi_dev_tx(priv, + &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr], + sizeof(struct iwl_tfd), + &out_cmd->hdr, firstlen, + skb->data + hdr_len, secondlen); + /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); ret = iwl_txq_update_write_ptr(priv, txq); @@ -1044,6 +1050,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) pci_unmap_addr_set(out_meta, mapping, phys_addr); pci_unmap_len_set(out_meta, len, fix_size); + trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags); + priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, phys_addr, fix_size, 1, U32_PAD(cmd->len)); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 3575e7fbadc7..d0d1b7f4c396 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1404,6 +1404,9 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) PCI_DMA_FROMDEVICE); pkt = (struct iwl_rx_packet *)rxb->skb->data; + trace_iwlwifi_dev_rx(priv, pkt, + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); + /* Reclaim a command buffer only if this packet is a response * to a (driver-originated) command. * If the packet (e.g. Rx frame) originated from uCode, @@ -1549,8 +1552,9 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv) "%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n", desc_lookup(desc), desc, time, blink1, blink2, ilink1, ilink2, data1); + trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, 0, + 0, blink1, blink2, ilink1, ilink2); } - } #define EVENT_START_OFFSET (6 * sizeof(u32)) @@ -1590,10 +1594,12 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, if (mode == 0) { /* data, ev */ IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); + trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); } else { data = iwl_read_targ_mem(priv, ptr); ptr += sizeof(u32); IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev); + trace_iwlwifi_dev_ucode_event(priv, time, data, ev); } } } -- cgit v1.2.3 From e932a609e9759cc75db0c234f465a5fd6e20d362 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 2 Oct 2009 13:44:03 -0700 Subject: iwlwifi: LED cleanup The iwlwifi drivers have LED blinking requirements that mac80211 cannot fulfill due to the use of just a single LED instead of different ones for TX, RX, radio etc. Instead, the single LED blinks according to transfers and is solid on the rest of the time. As such, having LED class devices registered that mac80211 triggers are connected to is pointless as we don't use the triggers anyway. Remove all the useless code and add hooks into the driver itself. At the same time, make the LED code abstracted so the core code that determines blink rate etc. can be shared between 3945 and agn in iwlcore. At the same time, the fact that we removed the use of the mac80211 LED triggers means we can also remove the IWLWIFI_LEDS Kconfig symbol since the LED support is now self-contained. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 9 - drivers/net/wireless/iwlwifi/Makefile | 5 +- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 + drivers/net/wireless/iwlwifi/iwl-3945-led.c | 371 ++-------------------------- drivers/net/wireless/iwlwifi/iwl-3945-led.h | 22 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 10 +- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 + drivers/net/wireless/iwlwifi/iwl-5000.c | 5 +- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 + drivers/net/wireless/iwlwifi/iwl-agn-led.c | 85 +++++++ drivers/net/wireless/iwlwifi/iwl-agn-led.h | 32 +++ drivers/net/wireless/iwlwifi/iwl-agn.c | 6 +- drivers/net/wireless/iwlwifi/iwl-core.c | 7 +- drivers/net/wireless/iwlwifi/iwl-core.h | 7 + drivers/net/wireless/iwlwifi/iwl-debug.h | 2 - drivers/net/wireless/iwlwifi/iwl-debugfs.c | 8 - drivers/net/wireless/iwlwifi/iwl-dev.h | 7 +- drivers/net/wireless/iwlwifi/iwl-led.c | 285 ++------------------- drivers/net/wireless/iwlwifi/iwl-led.h | 38 +-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 8 +- 21 files changed, 194 insertions(+), 721 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-agn-led.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-agn-led.h (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 48d8f2cf566c..c82c97be7bfa 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -2,15 +2,6 @@ config IWLWIFI tristate "Intel Wireless Wifi" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER - select MAC80211_LEDS if IWLWIFI_LEDS - select LEDS_CLASS if IWLWIFI_LEDS - -config IWLWIFI_LEDS - bool "Enable LED support in iwlagn and iwl3945 drivers" - depends on IWLWIFI - default y - ---help--- - Select this if you want LED support. config IWLWIFI_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwlagn driver" diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 3f31d866054b..7f82044af242 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,9 +1,8 @@ obj-$(CONFIG_IWLWIFI) += iwlcore.o iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o -iwlcore-objs += iwl-scan.o +iwlcore-objs += iwl-scan.o iwl-led.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o -iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o @@ -11,7 +10,7 @@ CFLAGS_iwl-devtrace.o := -I$(src) # AGN obj-$(CONFIG_IWLAGN) += iwlagn.o -iwlagn-objs := iwl-agn.o iwl-agn-rs.o +iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwlagn-$(CONFIG_IWL4965) += iwl-4965.o iwlagn-$(CONFIG_IWL5000) += iwl-5000.o diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index af91dbab255a..86d93b52c6fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -44,6 +44,7 @@ #include "iwl-sta.h" #include "iwl-helpers.h" #include "iwl-5000-hw.h" +#include "iwl-agn-led.h" /* Highest firmware API version supported */ #define IWL1000_UCODE_API_MAX 3 @@ -145,6 +146,7 @@ static struct iwl_ops iwl1000_ops = { .lib = &iwl1000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, + .led = &iwlagn_led_ops, }; struct iwl_cfg iwl1000_bgn_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index 8c29ded7d02c..a871d09d598f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -24,8 +24,6 @@ * *****************************************************************************/ -#ifdef CONFIG_IWLWIFI_LEDS - #include #include #include @@ -43,388 +41,51 @@ #include "iwl-3945.h" #include "iwl-core.h" #include "iwl-dev.h" +#include "iwl-3945-led.h" -#ifdef CONFIG_IWLWIFI_DEBUG -static const char *led_type_str[] = { - __stringify(IWL_LED_TRG_TX), - __stringify(IWL_LED_TRG_RX), - __stringify(IWL_LED_TRG_ASSOC), - __stringify(IWL_LED_TRG_RADIO), - NULL -}; -#endif /* CONFIG_IWLWIFI_DEBUG */ - -static const struct { - u16 brightness; - u8 on_time; - u8 off_time; -} blink_tbl[] = -{ - {300, 25, 25}, - {200, 40, 40}, - {100, 55, 55}, - {70, 65, 65}, - {50, 75, 75}, - {20, 85, 85}, - {15, 95, 95 }, - {10, 110, 110}, - {5, 130, 130}, - {0, 167, 167}, - /* SOLID_ON */ - {-1, IWL_LED_SOLID, 0} -}; - -#define IWL_1MB_RATE (128 * 1024) -#define IWL_LED_THRESHOLD (16) -#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/ -#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) - -static void iwl3945_led_cmd_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb) -{ -} - -static inline int iwl3945_brightness_to_idx(enum led_brightness brightness) -{ - return fls(0x000000FF & (u32)brightness); -} /* Send led command */ -static int iwl_send_led_cmd(struct iwl_priv *priv, - struct iwl_led_cmd *led_cmd) +static int iwl3945_send_led_cmd(struct iwl_priv *priv, + struct iwl_led_cmd *led_cmd) { struct iwl_host_cmd cmd = { .id = REPLY_LEDS_CMD, .len = sizeof(struct iwl_led_cmd), .data = led_cmd, .flags = CMD_ASYNC, - .callback = iwl3945_led_cmd_callback, + .callback = NULL, }; return iwl_send_cmd(priv, &cmd); } - - -/* Set led on command */ -static int iwl3945_led_pattern(struct iwl_priv *priv, int led_id, - unsigned int idx) -{ - struct iwl_led_cmd led_cmd = { - .id = led_id, - .interval = IWL_DEF_LED_INTRVL - }; - - BUG_ON(idx > IWL_MAX_BLINK_TBL); - - led_cmd.on = blink_tbl[idx].on_time; - led_cmd.off = blink_tbl[idx].off_time; - - return iwl_send_led_cmd(priv, &led_cmd); -} - - /* Set led on command */ -static int iwl3945_led_on(struct iwl_priv *priv, int led_id) +static int iwl3945_led_on(struct iwl_priv *priv) { struct iwl_led_cmd led_cmd = { - .id = led_id, + .id = IWL_LED_LINK, .on = IWL_LED_SOLID, .off = 0, .interval = IWL_DEF_LED_INTRVL }; - return iwl_send_led_cmd(priv, &led_cmd); + return iwl3945_send_led_cmd(priv, &led_cmd); } /* Set led off command */ -static int iwl3945_led_off(struct iwl_priv *priv, int led_id) +static int iwl3945_led_off(struct iwl_priv *priv) { struct iwl_led_cmd led_cmd = { - .id = led_id, + .id = IWL_LED_LINK, .on = 0, .off = 0, .interval = IWL_DEF_LED_INTRVL }; - IWL_DEBUG_LED(priv, "led off %d\n", led_id); - return iwl_send_led_cmd(priv, &led_cmd); + IWL_DEBUG_LED(priv, "led off\n"); + return iwl3945_send_led_cmd(priv, &led_cmd); } -/* - * Set led on in case of association - * */ -static int iwl3945_led_associate(struct iwl_priv *priv, int led_id) -{ - IWL_DEBUG_LED(priv, "Associated\n"); - - priv->allow_blinking = 1; - return iwl3945_led_on(priv, led_id); -} -/* Set Led off in case of disassociation */ -static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id) -{ - IWL_DEBUG_LED(priv, "Disassociated\n"); - - priv->allow_blinking = 0; - - return 0; -} - -/* - * brightness call back function for Tx/Rx LED - */ -static int iwl3945_led_associated(struct iwl_priv *priv, int led_id) -{ - if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - !test_bit(STATUS_READY, &priv->status)) - return 0; - - - /* start counting Tx/Rx bytes */ - if (!priv->last_blink_time && priv->allow_blinking) - priv->last_blink_time = jiffies; - return 0; -} - -/* - * brightness call back for association and radio - */ -static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct iwl_led *led = container_of(led_cdev, - struct iwl_led, led_dev); - struct iwl_priv *priv = led->priv; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n", - led_type_str[led->type], brightness); - - switch (brightness) { - case LED_FULL: - if (led->led_on) - led->led_on(priv, IWL_LED_LINK); - break; - case LED_OFF: - if (led->led_off) - led->led_off(priv, IWL_LED_LINK); - break; - default: - if (led->led_pattern) { - int idx = iwl3945_brightness_to_idx(brightness); - led->led_pattern(priv, IWL_LED_LINK, idx); - } - break; - } -} - -/* - * Register led class with the system - */ -static int iwl3945_led_register_led(struct iwl_priv *priv, - struct iwl_led *led, - enum led_type type, u8 set_led, - char *trigger) -{ - struct device *device = wiphy_dev(priv->hw->wiphy); - int ret; - - led->led_dev.name = led->name; - led->led_dev.brightness_set = iwl3945_led_brightness_set; - led->led_dev.default_trigger = trigger; - - led->priv = priv; - led->type = type; - - ret = led_classdev_register(device, &led->led_dev); - if (ret) { - IWL_ERR(priv, "Error: failed to register led handler.\n"); - return ret; - } - - led->registered = 1; - - if (set_led && led->led_on) - led->led_on(priv, IWL_LED_LINK); - return 0; -} - - -/* - * calculate blink rate according to last 2 sec Tx/Rx activities - */ -static inline u8 get_blink_rate(struct iwl_priv *priv) -{ - int index; - s64 tpt = priv->rxtxpackets; - - if (tpt < 0) - tpt = -tpt; - - IWL_DEBUG_LED(priv, "tpt %lld \n", (long long)tpt); - - if (!priv->allow_blinking) - index = IWL_MAX_BLINK_TBL; - else - for (index = 0; index < IWL_MAX_BLINK_TBL; index++) - if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE)) - break; - - IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", index); - return index; -} - -/* - * this function called from handler. Since setting Led command can - * happen very frequent we postpone led command to be called from - * REPLY handler so we know ucode is up - */ -void iwl3945_led_background(struct iwl_priv *priv) -{ - u8 blink_idx; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { - priv->last_blink_time = 0; - return; - } - if (iwl_is_rfkill(priv)) { - priv->last_blink_time = 0; - return; - } - - if (!priv->allow_blinking) { - priv->last_blink_time = 0; - if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { - priv->last_blink_rate = IWL_SOLID_BLINK_IDX; - iwl3945_led_pattern(priv, IWL_LED_LINK, - IWL_SOLID_BLINK_IDX); - } - return; - } - if (!priv->last_blink_time || - !time_after(jiffies, priv->last_blink_time + - msecs_to_jiffies(1000))) - return; - - blink_idx = get_blink_rate(priv); - - /* call only if blink rate change */ - if (blink_idx != priv->last_blink_rate) - iwl3945_led_pattern(priv, IWL_LED_LINK, blink_idx); - - priv->last_blink_time = jiffies; - priv->last_blink_rate = blink_idx; - priv->rxtxpackets = 0; -} - - -/* Register all led handler */ -int iwl3945_led_register(struct iwl_priv *priv) -{ - char *trigger; - int ret; - - priv->last_blink_rate = 0; - priv->rxtxpackets = 0; - priv->led_tpt = 0; - priv->last_blink_time = 0; - priv->allow_blinking = 0; - - trigger = ieee80211_get_radio_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_RADIO].name, - sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio", - wiphy_name(priv->hw->wiphy)); - - priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on; - priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off; - priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; - - ret = iwl3945_led_register_led(priv, - &priv->led[IWL_LED_TRG_RADIO], - IWL_LED_TRG_RADIO, 1, trigger); - - if (ret) - goto exit_fail; - - trigger = ieee80211_get_assoc_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_ASSOC].name, - sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc", - wiphy_name(priv->hw->wiphy)); - - ret = iwl3945_led_register_led(priv, - &priv->led[IWL_LED_TRG_ASSOC], - IWL_LED_TRG_ASSOC, 0, trigger); - - /* for assoc always turn led on */ - priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_associate; - priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_disassociate; - priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; - - if (ret) - goto exit_fail; - - trigger = ieee80211_get_rx_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_RX].name, - sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX", - wiphy_name(priv->hw->wiphy)); - - ret = iwl3945_led_register_led(priv, - &priv->led[IWL_LED_TRG_RX], - IWL_LED_TRG_RX, 0, trigger); - - priv->led[IWL_LED_TRG_RX].led_on = iwl3945_led_associated; - priv->led[IWL_LED_TRG_RX].led_off = iwl3945_led_associated; - priv->led[IWL_LED_TRG_RX].led_pattern = iwl3945_led_pattern; - - if (ret) - goto exit_fail; - - trigger = ieee80211_get_tx_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_TX].name, - sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX", - wiphy_name(priv->hw->wiphy)); - - ret = iwl3945_led_register_led(priv, - &priv->led[IWL_LED_TRG_TX], - IWL_LED_TRG_TX, 0, trigger); - - priv->led[IWL_LED_TRG_TX].led_on = iwl3945_led_associated; - priv->led[IWL_LED_TRG_TX].led_off = iwl3945_led_associated; - priv->led[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern; - - if (ret) - goto exit_fail; - - return 0; - -exit_fail: - iwl3945_led_unregister(priv); - return ret; -} - - -/* unregister led class */ -static void iwl3945_led_unregister_led(struct iwl_led *led, u8 set_led) -{ - if (!led->registered) - return; - - led_classdev_unregister(&led->led_dev); - - if (set_led) - led->led_dev.brightness_set(&led->led_dev, LED_OFF); - led->registered = 0; -} - -/* Unregister all led handlers */ -void iwl3945_led_unregister(struct iwl_priv *priv) -{ - iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0); - iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RX], 0); - iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_TX], 0); - iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1); -} - -#endif +const struct iwl_led_ops iwl3945_led_ops = { + .cmd = iwl3945_send_led_cmd, + .on = iwl3945_led_on, + .off = iwl3945_led_off, +}; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h index 3b65642258ca..5a1033ca7aaa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h @@ -24,23 +24,9 @@ * *****************************************************************************/ -#ifndef IWL3945_LEDS_H -#define IWL3945_LEDS_H +#ifndef __iwl_3945_led_h__ +#define __iwl_3945_led_h__ -struct iwl_priv; +extern const struct iwl_led_ops iwl3945_led_ops; -#ifdef CONFIG_IWLWIFI_LEDS - -#include "iwl-led.h" - -extern int iwl3945_led_register(struct iwl_priv *priv); -extern void iwl3945_led_unregister(struct iwl_priv *priv); -extern void iwl3945_led_background(struct iwl_priv *priv); - -#else -static inline int iwl3945_led_register(struct iwl_priv *priv) { return 0; } -static inline void iwl3945_led_unregister(struct iwl_priv *priv) {} -static inline void iwl3945_led_background(struct iwl_priv *priv) {} - -#endif /* IWLWIFI_LEDS*/ -#endif /* IWL3945_LEDS_H */ +#endif /* __iwl_3945_led_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 33e40c21eb72..f0ce5c45ca05 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -46,7 +46,8 @@ #include "iwl-eeprom.h" #include "iwl-helpers.h" #include "iwl-core.h" -#include "iwl-agn-rs.h" +#include "iwl-led.h" +#include "iwl-3945-led.h" #define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ @@ -359,7 +360,7 @@ void iwl3945_hw_rx_statistics(struct iwl_priv *priv, memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39)); - iwl3945_led_background(priv); + iwl_leds_background(priv); priv->last_statistics_time = jiffies; } @@ -572,10 +573,6 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, (struct ieee80211_hdr *)rxb->skb->data, le32_to_cpu(rx_end->status), stats); -#ifdef CONFIG_IWLWIFI_LEDS - 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)); @@ -2880,6 +2877,7 @@ static struct iwl_ops iwl3945_ops = { .lib = &iwl3945_lib, .hcmd = &iwl3945_hcmd, .utils = &iwl3945_hcmd_utils, + .led = &iwl3945_led_ops, }; static struct iwl_cfg iwl3945_bg_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 21679bf3a1aa..f3907c1079f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -46,7 +46,7 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; #include "iwl-debug.h" #include "iwl-power.h" #include "iwl-dev.h" -#include "iwl-3945-led.h" +#include "iwl-led.h" /* Highest firmware API version supported */ #define IWL3945_UCODE_API_MAX 2 diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 0921e454185b..8717946de011 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -44,6 +44,7 @@ #include "iwl-helpers.h" #include "iwl-calib.h" #include "iwl-sta.h" +#include "iwl-agn-led.h" static int iwl4965_send_tx_power(struct iwl_priv *priv); static int iwl4965_hw_get_temperature(struct iwl_priv *priv); @@ -2341,6 +2342,7 @@ static struct iwl_ops iwl4965_ops = { .lib = &iwl4965_lib, .hcmd = &iwl4965_hcmd, .utils = &iwl4965_hcmd_utils, + .led = &iwlagn_led_ops, }; struct iwl_cfg iwl4965_agn_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 01d53ebb96ad..624853503db1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -42,6 +42,7 @@ #include "iwl-io.h" #include "iwl-sta.h" #include "iwl-helpers.h" +#include "iwl-agn-led.h" #include "iwl-5000-hw.h" #include "iwl-6000-hw.h" @@ -1641,11 +1642,12 @@ static struct iwl_lib_ops iwl5150_lib = { }, }; -struct iwl_ops iwl5000_ops = { +static struct iwl_ops iwl5000_ops = { .ucode = &iwl5000_ucode, .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, + .led = &iwlagn_led_ops, }; static struct iwl_ops iwl5150_ops = { @@ -1653,6 +1655,7 @@ static struct iwl_ops iwl5150_ops = { .lib = &iwl5150_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, + .led = &iwlagn_led_ops, }; struct iwl_mod_params iwl50_mod_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 6f4ee27e07c9..a002214f4d49 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -45,6 +45,7 @@ #include "iwl-helpers.h" #include "iwl-5000-hw.h" #include "iwl-6000-hw.h" +#include "iwl-agn-led.h" /* Highest firmware API version supported */ #define IWL6000_UCODE_API_MAX 4 @@ -227,6 +228,7 @@ static struct iwl_ops iwl6000_ops = { .lib = &iwl6000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, + .led = &iwlagn_led_ops, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c new file mode 100644 index 000000000000..3bccba20f6da --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.c @@ -0,0 +1,85 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iwl-commands.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-agn-led.h" + +/* Send led command */ +static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl_led_cmd), + .data = led_cmd, + .flags = CMD_ASYNC, + .callback = NULL, + }; + u32 reg; + + reg = iwl_read32(priv, CSR_LED_REG); + if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) + iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); + + return iwl_send_cmd(priv, &cmd); +} + +/* Set led register off */ +static int iwl_led_on_reg(struct iwl_priv *priv) +{ + IWL_DEBUG_LED(priv, "led on\n"); + iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); + return 0; +} + +/* Set led register off */ +static int iwl_led_off_reg(struct iwl_priv *priv) +{ + IWL_DEBUG_LED(priv, "LED Reg off\n"); + iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); + return 0; +} + +const struct iwl_led_ops iwlagn_led_ops = { + .cmd = iwl_send_led_cmd, + .on = iwl_led_on_reg, + .off = iwl_led_off_reg, +}; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h new file mode 100644 index 000000000000..ab55f92a161d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_agn_led_h__ +#define __iwl_agn_led_h__ + +extern const struct iwl_led_ops iwlagn_led_ops; + +#endif /* __iwl_agn_led_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4fb50d0eb536..046b571fd9ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1801,7 +1801,7 @@ static void iwl_alive_start(struct iwl_priv *priv) /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); - iwl_leds_register(priv); + iwl_leds_init(priv); IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); set_bit(STATUS_READY, &priv->status); @@ -1839,8 +1839,6 @@ static void __iwl_down(struct iwl_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); - iwl_leds_unregister(priv); - iwl_clear_stations_table(priv); /* Unblock any waiting calls */ @@ -2339,6 +2337,8 @@ static int iwl_mac_start(struct ieee80211_hw *hw) } } + iwl_led_start(priv); + out: priv->is_open = 1; IWL_DEBUG_MAC80211(priv, "leave\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1cf2e04fe3f9..34547cf3a66e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2384,6 +2384,8 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, priv->timestamp = bss_conf->timestamp; priv->assoc_capability = bss_conf->assoc_capability; + iwl_led_associate(priv); + /* * We have just associated, don't start scan too early * leave time for EAPOL exchange to complete. @@ -2394,9 +2396,10 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; if (!iwl_is_rfkill(priv)) priv->cfg->ops->lib->post_associate(priv); - } else + } else { priv->assoc_id = 0; - + iwl_led_disassociate(priv); + } } if (changes && iwl_is_associated(priv) && priv->assoc_id) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3bd0e59bb5a4..eb586a546181 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -187,11 +187,18 @@ struct iwl_lib_ops { struct iwl_temp_ops temp_ops; }; +struct iwl_led_ops { + int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd); + int (*on)(struct iwl_priv *priv); + int (*off)(struct iwl_priv *priv); +}; + struct iwl_ops { const struct iwl_ucode_ops *ucode; const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; + const struct iwl_led_ops *led; }; struct iwl_mod_params { diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index cbc62904655d..b9ca475cc61c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -84,9 +84,7 @@ struct iwl_debugfs { struct dentry *file_interrupt; struct dentry *file_qos; struct dentry *file_thermal_throttling; -#ifdef CONFIG_IWLWIFI_LEDS struct dentry *file_led; -#endif struct dentry *file_disable_ht40; struct dentry *file_sleep_level_override; struct dentry *file_current_sleep_command; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index fa6371d171c5..1794b9c4e6ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -677,7 +677,6 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, return ret; } -#ifdef CONFIG_IWLWIFI_LEDS static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -702,7 +701,6 @@ static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); return ret; } -#endif static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, char __user *user_buf, @@ -866,9 +864,7 @@ DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(qos); -#ifdef CONFIG_IWLWIFI_LEDS 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); @@ -1666,9 +1662,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(status, data); DEBUGFS_ADD_FILE(interrupt, data); DEBUGFS_ADD_FILE(qos, data); -#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); @@ -1721,9 +1715,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos); -#ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led); -#endif 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); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ad99ce7824c6..eabc55695aff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -43,7 +43,6 @@ #include "iwl-debug.h" #include "iwl-4965-hw.h" #include "iwl-3945-hw.h" -#include "iwl-3945-led.h" #include "iwl-led.h" #include "iwl-power.h" #include "iwl-agn-rs.h" @@ -73,7 +72,6 @@ struct iwl_tx_queue; /* shared structures from iwl-5000.c */ extern struct iwl_mod_params iwl50_mod_params; -extern struct iwl_ops iwl5000_ops; extern struct iwl_ucode_ops iwl5000_ucode; extern struct iwl_lib_ops iwl5000_lib; extern struct iwl_hcmd_ops iwl5000_hcmd; @@ -1066,14 +1064,11 @@ struct iwl_priv { struct iwl_init_alive_resp card_alive_init; struct iwl_alive_resp card_alive; -#ifdef CONFIG_IWLWIFI_LEDS unsigned long last_blink_time; u8 last_blink_rate; u8 allow_blinking; u64 led_tpt; - struct iwl_led led[IWL_LED_TRG_MAX]; - unsigned int rxtxpackets; -#endif + u16 active_rate; u16 active_rate_basic; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 685ba9d6f082..478c90511ebf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -48,16 +48,6 @@ module_param(led_mode, int, S_IRUGO); MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), " "(default 0)\n"); -#ifdef CONFIG_IWLWIFI_DEBUG -static const char *led_type_str[] = { - __stringify(IWL_LED_TRG_TX), - __stringify(IWL_LED_TRG_RX), - __stringify(IWL_LED_TRG_ASSOC), - __stringify(IWL_LED_TRG_RADIO), - NULL -}; -#endif /* CONFIG_IWLWIFI_DEBUG */ - static const struct { u16 tpt; /* Mb/s */ @@ -75,7 +65,7 @@ static const struct { {5, 110, 110}, {1, 130, 130}, {0, 167, 167}, -/* SOLID_ON */ + /* SOLID_ON */ {-1, IWL_LED_SOLID, 0} }; @@ -107,37 +97,11 @@ static inline u8 iwl_blink_compensation(struct iwl_priv *priv, return (u8)((time * compensation) >> 6); } -/* [0-256] -> [0..8] FIXME: we need [0..10] */ -static inline int iwl_brightness_to_idx(enum led_brightness brightness) -{ - return fls(0x000000FF & (u32)brightness); -} - -/* Send led command */ -static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) -{ - struct iwl_host_cmd cmd = { - .id = REPLY_LEDS_CMD, - .len = sizeof(struct iwl_led_cmd), - .data = led_cmd, - .flags = CMD_ASYNC, - .callback = NULL, - }; - u32 reg; - - reg = iwl_read32(priv, CSR_LED_REG); - if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) - iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); - - return iwl_send_cmd(priv, &cmd); -} - /* Set led pattern command */ -static int iwl_led_pattern(struct iwl_priv *priv, int led_id, - unsigned int idx) +static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx) { struct iwl_led_cmd led_cmd = { - .id = led_id, + .id = IWL_LED_LINK, .interval = IWL_DEF_LED_INTRVL }; @@ -152,153 +116,32 @@ static int iwl_led_pattern(struct iwl_priv *priv, int led_id, iwl_blink_compensation(priv, blink_tbl[idx].off_time, priv->cfg->led_compensation); - return iwl_send_led_cmd(priv, &led_cmd); -} - -/* Set led register off */ -static int iwl_led_on_reg(struct iwl_priv *priv, int led_id) -{ - IWL_DEBUG_LED(priv, "led on %d\n", led_id); - iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); - return 0; -} - -#if 0 -/* Set led on command */ -static int iwl_led_on(struct iwl_priv *priv, int led_id) -{ - struct iwl_led_cmd led_cmd = { - .id = led_id, - .on = IWL_LED_SOLID, - .off = 0, - .interval = IWL_DEF_LED_INTRVL - }; - return iwl_send_led_cmd(priv, &led_cmd); -} - -/* Set led off command */ -int iwl_led_off(struct iwl_priv *priv, int led_id) -{ - struct iwl_led_cmd led_cmd = { - .id = led_id, - .on = 0, - .off = 0, - .interval = IWL_DEF_LED_INTRVL - }; - IWL_DEBUG_LED(priv, "led off %d\n", led_id); - return iwl_send_led_cmd(priv, &led_cmd); + return priv->cfg->ops->led->cmd(priv, &led_cmd); } -#endif - -/* Set led register off */ -static int iwl_led_off_reg(struct iwl_priv *priv, int led_id) +int iwl_led_start(struct iwl_priv *priv) { - IWL_DEBUG_LED(priv, "LED Reg off\n"); - iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); - return 0; + return priv->cfg->ops->led->on(priv); } +EXPORT_SYMBOL(iwl_led_start); -/* - * Set led register in case of disassociation according to rfkill state - */ -static int iwl_led_associate(struct iwl_priv *priv, int led_id) +int iwl_led_associate(struct iwl_priv *priv) { IWL_DEBUG_LED(priv, "Associated\n"); if (led_mode == IWL_LED_BLINK) priv->allow_blinking = 1; - return iwl_led_on_reg(priv, led_id); -} -static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) -{ - priv->allow_blinking = 0; - - return 0; -} - -/* - * brightness call back function for Tx/Rx LED - */ -static int iwl_led_associated(struct iwl_priv *priv, int led_id) -{ - if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - !test_bit(STATUS_READY, &priv->status)) - return 0; - + priv->last_blink_time = jiffies; - /* start counting Tx/Rx bytes */ - if (!priv->last_blink_time && priv->allow_blinking) - priv->last_blink_time = jiffies; return 0; } -/* - * brightness call back for association and radio - */ -static void iwl_led_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brightness) +int iwl_led_disassociate(struct iwl_priv *priv) { - struct iwl_led *led = container_of(led_cdev, struct iwl_led, led_dev); - struct iwl_priv *priv = led->priv; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - - IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n", - led_type_str[led->type], brightness); - switch (brightness) { - case LED_FULL: - if (led->led_on) - led->led_on(priv, IWL_LED_LINK); - break; - case LED_OFF: - if (led->led_off) - led->led_off(priv, IWL_LED_LINK); - break; - default: - if (led->led_pattern) { - int idx = iwl_brightness_to_idx(brightness); - led->led_pattern(priv, IWL_LED_LINK, idx); - } - break; - } -} - - - -/* - * Register led class with the system - */ -static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led, - enum led_type type, u8 set_led, - char *trigger) -{ - struct device *device = wiphy_dev(priv->hw->wiphy); - int ret; - - led->led_dev.name = led->name; - led->led_dev.brightness_set = iwl_led_brightness_set; - led->led_dev.default_trigger = trigger; - - led->priv = priv; - led->type = type; - - ret = led_classdev_register(device, &led->led_dev); - if (ret) { - IWL_ERR(priv, "Error: failed to register led handler.\n"); - return ret; - } - - led->registered = 1; - - if (set_led && led->led_on) - led->led_on(priv, IWL_LED_LINK); + priv->allow_blinking = 0; return 0; } - /* * calculate blink rate according to last second Tx/Rx activities */ @@ -324,7 +167,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) i = IWL_MAX_BLINK_TBL; else for (i = 0; i < IWL_MAX_BLINK_TBL; i++) - if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) + if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) break; IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", i); @@ -353,8 +196,7 @@ void iwl_leds_background(struct iwl_priv *priv) priv->last_blink_time = 0; if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { priv->last_blink_rate = IWL_SOLID_BLINK_IDX; - iwl_led_pattern(priv, IWL_LED_LINK, - IWL_SOLID_BLINK_IDX); + iwl_led_pattern(priv, IWL_SOLID_BLINK_IDX); } return; } @@ -367,111 +209,18 @@ void iwl_leds_background(struct iwl_priv *priv) /* call only if blink rate change */ if (blink_idx != priv->last_blink_rate) - iwl_led_pattern(priv, IWL_LED_LINK, blink_idx); + iwl_led_pattern(priv, blink_idx); priv->last_blink_time = jiffies; priv->last_blink_rate = blink_idx; } +EXPORT_SYMBOL(iwl_leds_background); -/* Register all led handler */ -int iwl_leds_register(struct iwl_priv *priv) +void iwl_leds_init(struct iwl_priv *priv) { - char *trigger; - int ret; - priv->last_blink_rate = 0; priv->led_tpt = 0; priv->last_blink_time = 0; priv->allow_blinking = 0; - - trigger = ieee80211_get_radio_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_RADIO].name, - sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio", - wiphy_name(priv->hw->wiphy)); - - priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg; - priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg; - priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; - - ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO], - IWL_LED_TRG_RADIO, 1, trigger); - if (ret) - goto exit_fail; - - trigger = ieee80211_get_assoc_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_ASSOC].name, - sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc", - wiphy_name(priv->hw->wiphy)); - - ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC], - IWL_LED_TRG_ASSOC, 0, trigger); - - /* for assoc always turn led on */ - priv->led[IWL_LED_TRG_ASSOC].led_on = iwl_led_associate; - priv->led[IWL_LED_TRG_ASSOC].led_off = iwl_led_disassociate; - priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; - - if (ret) - goto exit_fail; - - trigger = ieee80211_get_rx_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_RX].name, - sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX", - wiphy_name(priv->hw->wiphy)); - - ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX], - IWL_LED_TRG_RX, 0, trigger); - - priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated; - priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated; - priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern; - - if (ret) - goto exit_fail; - - trigger = ieee80211_get_tx_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_TX].name, - sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX", - wiphy_name(priv->hw->wiphy)); - - ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX], - IWL_LED_TRG_TX, 0, trigger); - - priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated; - priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated; - priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern; - - if (ret) - goto exit_fail; - - return 0; - -exit_fail: - iwl_leds_unregister(priv); - return ret; } -EXPORT_SYMBOL(iwl_leds_register); - -/* unregister led class */ -static void iwl_leds_unregister_led(struct iwl_led *led, u8 set_led) -{ - if (!led->registered) - return; - - led_classdev_unregister(&led->led_dev); - - if (set_led) - led->led_dev.brightness_set(&led->led_dev, LED_OFF); - led->registered = 0; -} - -/* Unregister all led handlers */ -void iwl_leds_unregister(struct iwl_priv *priv) -{ - iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0); - iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RX], 0); - iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_TX], 0); - iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1); -} -EXPORT_SYMBOL(iwl_leds_unregister); - +EXPORT_SYMBOL(iwl_leds_init); diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index dd76b266c633..f47f053f02ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -30,9 +30,6 @@ struct iwl_priv; -#ifdef CONFIG_IWLWIFI_LEDS -#include - #define IWL_LED_SOLID 11 #define IWL_LED_NAME_LEN 31 #define IWL_DEF_LED_INTRVL cpu_to_le32(1000) @@ -59,38 +56,11 @@ enum iwl_led_mode { IWL_LED_BLINK, IWL_LED_RF_STATE, }; -#endif - -#ifdef CONFIG_IWLWIFI_LEDS - -struct iwl_led { - struct iwl_priv *priv; - struct led_classdev led_dev; - char name[32]; - - int (*led_on) (struct iwl_priv *priv, int led_id); - int (*led_off) (struct iwl_priv *priv, int led_id); - int (*led_pattern) (struct iwl_priv *priv, int led_id, unsigned int idx); - enum led_type type; - unsigned int registered; -}; - -int iwl_leds_register(struct iwl_priv *priv); -void iwl_leds_unregister(struct iwl_priv *priv); +void iwl_leds_init(struct iwl_priv *priv); void iwl_leds_background(struct iwl_priv *priv); +int iwl_led_start(struct iwl_priv *priv); +int iwl_led_associate(struct iwl_priv *priv); +int iwl_led_disassociate(struct iwl_priv *priv); -#else -static inline int iwl_leds_register(struct iwl_priv *priv) -{ - return 0; -} -static inline void iwl_leds_unregister(struct iwl_priv *priv) -{ -} -static inline void iwl_leds_background(struct iwl_priv *priv) -{ -} - -#endif /* CONFIG_IWLWIFI_LEDS */ #endif /* __iwl_leds_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index d0d1b7f4c396..ecbe036ecb63 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -455,9 +455,6 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, tx->timeout.pm_frame_timeout = cpu_to_le16(2); } else { tx->timeout.pm_frame_timeout = 0; -#ifdef CONFIG_IWLWIFI_LEDS - priv->rxtxpackets += le16_to_cpu(cmd->cmd.tx.len); -#endif } tx->driver_txop = 0; @@ -2483,7 +2480,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) iwl3945_reg_txpower_periodic(priv); - iwl3945_led_register(priv); + iwl_leds_init(priv); IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); set_bit(STATUS_READY, &priv->status); @@ -2521,7 +2518,6 @@ static void __iwl3945_down(struct iwl_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); - iwl3945_led_unregister(priv); iwl_clear_stations_table(priv); /* Unblock any waiting calls */ @@ -3156,6 +3152,8 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) * no need to poll the killswitch state anymore */ cancel_delayed_work(&priv->rfkill_poll); + iwl_led_start(priv); + priv->is_open = 1; IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; -- cgit v1.2.3 From d68b603cf01a6e7d8c85c5a86db751ed3960c0c7 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 2 Oct 2009 13:44:04 -0700 Subject: iwlwifi/iwl3945 : unify apm stop operation Unify the usage of apm_stop_master and apm_stop across all hardwares. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 43 ++---------------------------- drivers/net/wireless/iwlwifi/iwl-4965.c | 38 ++------------------------- drivers/net/wireless/iwlwifi/iwl-5000.c | 46 +++------------------------------ drivers/net/wireless/iwlwifi/iwl-6000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 36 ++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 3 ++- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 8 files changed, 47 insertions(+), 124 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 86d93b52c6fc..679a67ff76eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -112,7 +112,7 @@ static struct iwl_lib_ops iwl1000_lib = { .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, - .stop = iwl5000_apm_stop, + .stop = iwl_apm_stop, .config = iwl1000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index f0ce5c45ca05..c5d1d57b4e0b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1167,48 +1167,9 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) iwl3945_hw_txq_ctx_free(priv); } -static int iwl3945_apm_stop_master(struct iwl_priv *priv) -{ - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - /* set stop master bit */ - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - - iwl_poll_direct_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - - if (ret < 0) - goto out; - -out: - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO(priv, "stop master\n"); - - return ret; -} - -static void iwl3945_apm_stop(struct iwl_priv *priv) -{ - unsigned long flags; - - iwl3945_apm_stop_master(priv); - - spin_lock_irqsave(&priv->lock, flags); - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - - udelay(10); - /* clear "init complete" move adapter D0A* --> D0U state */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - spin_unlock_irqrestore(&priv->lock, flags); -} - static int iwl3945_apm_reset(struct iwl_priv *priv) { - iwl3945_apm_stop_master(priv); + iwl_apm_stop_master(priv); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); @@ -2841,7 +2802,7 @@ static struct iwl_lib_ops iwl3945_lib = { .apm_ops = { .init = iwl3945_apm_init, .reset = iwl3945_apm_reset, - .stop = iwl3945_apm_stop, + .stop = iwl_apm_stop, .config = iwl3945_nic_config, .set_pwr_src = iwl3945_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 8717946de011..dd10c426ecc4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -396,45 +396,11 @@ static void iwl4965_nic_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static int iwl4965_apm_stop_master(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - /* set stop master bit */ - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - - iwl_poll_direct_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO(priv, "stop master\n"); - - return 0; -} - -static void iwl4965_apm_stop(struct iwl_priv *priv) -{ - unsigned long flags; - - iwl4965_apm_stop_master(priv); - - spin_lock_irqsave(&priv->lock, flags); - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - - udelay(10); - /* clear "init complete" move adapter D0A* --> D0U state */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - spin_unlock_irqrestore(&priv->lock, flags); -} - static int iwl4965_apm_reset(struct iwl_priv *priv) { int ret = 0; - iwl4965_apm_stop_master(priv); + iwl_apm_stop_master(priv); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); @@ -2306,7 +2272,7 @@ static struct iwl_lib_ops iwl4965_lib = { .apm_ops = { .init = iwl4965_apm_init, .reset = iwl4965_apm_reset, - .stop = iwl4965_apm_stop, + .stop = iwl_apm_stop, .config = iwl4965_nic_config, .set_pwr_src = iwl_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 624853503db1..d8dadbf04138 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -72,26 +72,6 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = { IWL_TX_FIFO_HCCA_2 }; -/* FIXME: same implementation as 4965 */ -static int iwl5000_apm_stop_master(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - /* set stop master bit */ - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - - iwl_poll_direct_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO(priv, "stop master\n"); - - return 0; -} - - int iwl5000_apm_init(struct iwl_priv *priv) { int ret = 0; @@ -137,31 +117,11 @@ int iwl5000_apm_init(struct iwl_priv *priv) return ret; } -/* FIXME: this is identical to 4965 */ -void iwl5000_apm_stop(struct iwl_priv *priv) -{ - unsigned long flags; - - iwl5000_apm_stop_master(priv); - - spin_lock_irqsave(&priv->lock, flags); - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - - udelay(10); - - /* clear "init complete" move adapter D0A* --> D0U state */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - spin_unlock_irqrestore(&priv->lock, flags); -} - - int iwl5000_apm_reset(struct iwl_priv *priv) { int ret = 0; - iwl5000_apm_stop_master(priv); + iwl_apm_stop_master(priv); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); @@ -1561,7 +1521,7 @@ struct iwl_lib_ops iwl5000_lib = { .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, - .stop = iwl5000_apm_stop, + .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, @@ -1613,7 +1573,7 @@ static struct iwl_lib_ops iwl5150_lib = { .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, - .stop = iwl5000_apm_stop, + .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a002214f4d49..d1f0b0b4ad0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -193,7 +193,7 @@ static struct iwl_lib_ops iwl6000_lib = { .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, - .stop = iwl5000_apm_stop, + .stop = iwl_apm_stop, .config = iwl6000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 34547cf3a66e..7c0ef8e4ebbf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1329,6 +1329,42 @@ void iwl_irq_handle_error(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_irq_handle_error); +int iwl_apm_stop_master(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* set stop master bit */ + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + iwl_poll_direct_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO(priv, "stop master\n"); + + return 0; +} +EXPORT_SYMBOL(iwl_apm_stop_master); + +void iwl_apm_stop(struct iwl_priv *priv) +{ + unsigned long flags; + + iwl_apm_stop_master(priv); + + spin_lock_irqsave(&priv->lock, flags); + + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + udelay(10); + /* clear "init complete" move adapter D0A* --> D0U state */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL(iwl_apm_stop); + void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index eb586a546181..6688b6944200 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -658,6 +658,8 @@ extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); +void iwl_apm_stop(struct iwl_priv *priv); +int iwl_apm_stop_master(struct iwl_priv *priv); void iwl_setup_rxon_timing(struct iwl_priv *priv); static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) @@ -677,5 +679,4 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode( { return priv->hw->wiphy->bands[band]; } - #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index eabc55695aff..72946c144be7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -86,7 +86,6 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, extern int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp); extern int iwl5000_apm_init(struct iwl_priv *priv); -extern void iwl5000_apm_stop(struct iwl_priv *priv); extern int iwl5000_apm_reset(struct iwl_priv *priv); extern void iwl5000_nic_config(struct iwl_priv *priv); extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv); -- cgit v1.2.3 From 1739d3322008fb95e88ad0530bcc057789107879 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 2 Oct 2009 13:44:05 -0700 Subject: iwlwifi: replace iwl_poll_direct_bit with iwl_poll_bit for CSR access Replace iwl_poll_direct_bit with iwl_poll_bit when accessing CSR registers. There is no need to power up the mac to access CSR registers. Signed-off-by: Abhijeet Kolekar Acked-by: Ben M Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 10 ++++++---- drivers/net/wireless/iwlwifi/iwl-4965.c | 6 ++++-- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 ++++-- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 12 ++++++++---- 5 files changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index c5d1d57b4e0b..ced0e33e44b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -999,8 +999,9 @@ static int iwl3945_apm_init(struct iwl_priv *priv) * D0U* --> D0A* state */ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO(priv, "Failed to init the card\n"); goto out; @@ -1177,8 +1178,9 @@ static int iwl3945_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - iwl_poll_direct_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_BSM_CLK_RQT); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index dd10c426ecc4..f8eed9a4abc1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -335,7 +335,8 @@ static int iwl4965_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO(priv, "Failed to init the card\n"); @@ -411,7 +412,8 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d8dadbf04138..98baf8af6da8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -98,7 +98,8 @@ int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO(priv, "Failed to init the card\n"); @@ -138,7 +139,8 @@ int iwl5000_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO(priv, "Failed to init the card\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7c0ef8e4ebbf..dc7fd87bed98 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1338,7 +1338,7 @@ int iwl_apm_stop_master(struct iwl_priv *priv) /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - iwl_poll_direct_bit(priv, CSR_RESET, + iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 3d2b93a61e62..8107132ab66c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -283,7 +283,8 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_poll_direct_bit(priv, CSR_HW_IF_CONFIG_REG, + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, EEPROM_SEM_TIMEOUT); if (ret >= 0) { @@ -322,7 +323,8 @@ static int iwl_init_otp_access(struct iwl_priv *priv) CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock to be ready */ - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) @@ -345,7 +347,8 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) _iwl_write32(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + ret = iwl_poll_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, CSR_EEPROM_REG_READ_VALID_MSK, IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { @@ -538,7 +541,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) _iwl_write32(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + ret = iwl_poll_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, CSR_EEPROM_REG_READ_VALID_MSK, IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { -- cgit v1.2.3 From f41bb897f202d23a7d896c716002a3d6050b991e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 2 Oct 2009 13:44:06 -0700 Subject: iwlwifi: validate the signature for EEPROM and OTP Both 1000 & 6000 series NICs contain on-chip OTP memory that replaces the off-chip EEPROM memory. The nature of OTP means there is a limited number of times a particular board can go through the factory flow and be (re)calibrated. As a consequence there will be some boards that contain EEPROM memory because OTP blocks were full. In the signature validation routine, iwlwifi needs to make sure "select bit" and "EEPROM/OTP signature" agree on the type of NVM to be used to configure the system. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-csr.h | 7 ++++++- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 33 ++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 06437d13e73e..8f183e0fa512 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -230,13 +230,18 @@ /* EEPROM GP */ #define CSR_EEPROM_GP_VALID_MSK (0x00000007) -#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) #define CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */ #define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ #define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ #define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ +/* EEPROM signature */ +#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000) +#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001) +#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002) +#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004) + /* CSR GIO */ #define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 8107132ab66c..e3dbd79cd13e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -215,12 +215,35 @@ static const struct iwl_txpwr_section enhinfo[] = { int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) { - u32 gp = iwl_read32(priv, CSR_EEPROM_GP); - if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { - IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); - return -ENOENT; + u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; + int ret = 0; + + IWL_DEBUG_INFO(priv, "EEPROM signature=0x%08x\n", gp); + switch (gp) { + case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP: + if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) { + IWL_ERR(priv, "EEPROM with bad signature: 0x%08x\n", + gp); + ret = -ENOENT; + } + break; + case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K: + case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K: + if (priv->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) { + IWL_ERR(priv, "OTP with bad signature: 0x%08x\n", gp); + ret = -ENOENT; + } + break; + case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP: + default: + IWL_ERR(priv, "bad EEPROM/OTP signature, type=%s, " + "EEPROM_GP=0x%08x\n", + (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + ? "OTP" : "EEPROM", gp); + ret = -ENOENT; + break; } - return 0; + return ret; } EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); -- cgit v1.2.3 From f33269b8968d1c64772a9221e2c9c42d07a9b5ae Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:19 -0700 Subject: iwl3945: update iwl3945_apm_init() Update iwl3945_apm_init() to set up device registers in sequence most recently recommended by factory. Add resets for APMG interrupts and radio chip, formerly done only in iwl3945_apm_reset(); moving them here assures that apm_init() will do a complete job of preparing hardware not only after platform boot, but also after apm_stop() has executed (due to rfkill, ifconfig down, driver unload, etc.). This is in preparation to completely remove apm_reset(). Add some comments. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 42 ++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 4115672e2338..89f82396a13a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -982,23 +982,45 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) return rc; } +/* + * Start up NIC's basic functionality after it has been reset + * (e.g. after platform boot, or shutdown via iwl3945_apm_stop()) + * NOTE: This does not load uCode nor start the embedded processor + */ static int iwl3945_apm_init(struct iwl_priv *priv) { int ret; iwl_power_initialize(priv); + /* Configure chip clock phase-lock-loop */ + iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL); + + /* + * Disable L0S exit timer (platform NMI Work/Around) + * (does this do anything on 3945, or just 4965 and beyond?) + */ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */ + /* Disable L0s without affecting L1; don't wait for ICH (L0s bug W/A) */ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - /* set "initialization complete" bit to move adapter - * D0U* --> D0A* state */ + /* Set FH wait threshold to maximum (HW error during stress W/A) */ + iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); + + /* + * Set "initialization complete" bit to move adapter from + * D0U* --> D0A* (powered-up active) state. + */ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + /* + * Wait for clock stabilization; once stabilized, access to + * device-internal resources is supported, e.g. iwl_write_prph() + * and accesses to uCode SRAM. + */ ret = iwl_poll_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); @@ -1007,13 +1029,21 @@ static int iwl3945_apm_init(struct iwl_priv *priv) goto out; } - /* enable DMA */ + /* Enable DMA and BSM clocks, wait for them to stabilize */ iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); - udelay(20); - /* disable L1-Active */ + /* Clear APMG (NIC's internal power management) interrupts */ + iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); + iwl_write_prph(priv, APMG_RTC_INT_STT_REG, 0xFFFFFFFF); + + /* Reset radio chip */ + iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); + udelay(5); + iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); + + /* Disable L1-Active */ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); -- cgit v1.2.3 From 4d2ccdb94847248a4075414169108d8f929c153c Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:20 -0700 Subject: iwlwifi: turn off device when not used. In some cases (e.g. when mac80211 calls iwl_mac_stop() for suspend or user no longer wants device active), device has not been going into low power state via __iwl_down(). apm_ops.reset() does not put device into low power state; instead it resets the device, then puts it into a powered-up state ready to be re-loaded with uCode and re-started. This has needlessly warmed up user's laptops and drained batteries. With current architecture in which mac80211 controls device up/down (including resetting device after firmware errors), there is no need for apm_ops.reset() any more; apm_ops.reset() is basically a combination of apm_ops.stop() and apm_ops.init(). Instead, __iwl_down() now unconditionally places the device into a low-power state via apm_ops.stop(). Device may be re-started via __iwl_up() calling apm_ops.init() as soon as it may be needed (e.g. quickly for firmware errors), but in the meantime, device will stop wasting energy. Note that, even in this low power state, if driver re-enables interrupts, the device retains the ability to sense the hardware RF-KILL switch, and (except for 3945) interrupt the host when it changes. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 +++----- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 ++---- 2 files changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8d7bc38fe005..0878b34ee586 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1899,11 +1899,9 @@ static void __iwl_down(struct iwl_priv *priv) udelay(5); - /* FIXME: apm_ops.suspend(priv) */ - if (exit_pending) - priv->cfg->ops->lib->apm_ops.stop(priv); - else - priv->cfg->ops->lib->apm_ops.reset(priv); + /* Stop the device, and put it in low power state */ + priv->cfg->ops->lib->apm_ops.stop(priv); + exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c347d6631d85..adf4ebe6bb78 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2576,10 +2576,8 @@ static void __iwl3945_down(struct iwl_priv *priv) udelay(5); - if (exit_pending) - priv->cfg->ops->lib->apm_ops.stop(priv); - else - priv->cfg->ops->lib->apm_ops.reset(priv); + /* Stop the device, and put it in low power state */ + priv->cfg->ops->lib->apm_ops.stop(priv); exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); -- cgit v1.2.3 From 278d84051d1944080d4cfdba205af5f5ce4f4064 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:21 -0700 Subject: iwl3945: remove unnecessary call to apm_ops.reset() Now that we're unconditionally using apm_ops.stop() to reset and power-down the device in __iwl3945_down(), the apm_ops.reset() is redundant. Removing this call will also allow us to remove iwl3945_apm_reset(). Remove unneeded iwl_clear_bit(CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ) because this bit will be set again very soon in iwl3945_hw_txq_ctx_stop() and other following calls. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index adf4ebe6bb78..ab4c4bae7600 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2563,11 +2563,6 @@ static void __iwl3945_down(struct iwl_priv *priv) test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; - priv->cfg->ops->lib->apm_ops.reset(priv); - spin_lock_irqsave(&priv->lock, flags); - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - spin_unlock_irqrestore(&priv->lock, flags); - iwl3945_hw_txq_ctx_stop(priv); iwl3945_hw_rxq_stop(priv); -- cgit v1.2.3 From b660d3adb8dd4ead54744c9269bae9338163020a Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:22 -0700 Subject: iwlagn, iwl3945: remove apm_reset() functions Clean up device-specific apm_reset() functions and library infrastructure, now that these reset() functions are no longer being used. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 - drivers/net/wireless/iwlwifi/iwl-3945.c | 42 ------------------------------ drivers/net/wireless/iwlwifi/iwl-4965.c | 41 ------------------------------ drivers/net/wireless/iwlwifi/iwl-5000.c | 45 --------------------------------- drivers/net/wireless/iwlwifi/iwl-6000.c | 1 - drivers/net/wireless/iwlwifi/iwl-core.h | 1 - drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 7 files changed, 132 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 679a67ff76eb..1fc38142a491 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -111,7 +111,6 @@ static struct iwl_lib_ops iwl1000_lib = { .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, - .reset = iwl5000_apm_reset, .stop = iwl_apm_stop, .config = iwl1000_nic_config, .set_pwr_src = iwl_set_pwr_src, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 89f82396a13a..f8ce96c94c6b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1198,47 +1198,6 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) iwl3945_hw_txq_ctx_free(priv); } -static int iwl3945_apm_reset(struct iwl_priv *priv) -{ - iwl_apm_stop_master(priv); - - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - udelay(10); - - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - - iwl_write_prph(priv, APMG_CLK_CTRL_REG, - APMG_CLK_VAL_BSM_CLK_RQT); - - iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); - iwl_write_prph(priv, APMG_RTC_INT_STT_REG, - 0xFFFFFFFF); - - /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); - udelay(10); - - iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); - udelay(5); - iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); - - /* Clear the 'host command active' bit... */ - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - - wake_up_interruptible(&priv->wait_command_queue); - - return 0; -} - /** * iwl3945_hw_reg_adjust_power_by_temp * return index delta into power gain settings table @@ -2833,7 +2792,6 @@ static struct iwl_lib_ops iwl3945_lib = { .dump_nic_error_log = iwl3945_dump_nic_error_log, .apm_ops = { .init = iwl3945_apm_init, - .reset = iwl3945_apm_reset, .stop = iwl_apm_stop, .config = iwl3945_nic_config, .set_pwr_src = iwl3945_set_pwr_src, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f8eed9a4abc1..782a36198f38 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -397,46 +397,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static int iwl4965_apm_reset(struct iwl_priv *priv) -{ - int ret = 0; - - iwl_apm_stop_master(priv); - - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - - udelay(10); - - /* FIXME: put here L1A -L0S w/a */ - - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret < 0) - goto out; - - udelay(10); - - /* Enable DMA and BSM Clock */ - iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); - - udelay(10); - - /* disable L1A */ - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - -out: - return ret; -} - /* Reset differential Rx gains in NIC to prepare for chain noise calibration. * Called after every association, but this runs only once! * ... once chain noise is calibrated the first time, it's good forever. */ @@ -2273,7 +2233,6 @@ static struct iwl_lib_ops iwl4965_lib = { .dump_nic_error_log = iwl_dump_nic_error_log, .apm_ops = { .init = iwl4965_apm_init, - .reset = iwl4965_apm_reset, .stop = iwl_apm_stop, .config = iwl4965_nic_config, .set_pwr_src = iwl_set_pwr_src, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 8cc3d50e7f59..33b38aa0d8c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -118,49 +118,6 @@ int iwl5000_apm_init(struct iwl_priv *priv) return ret; } -int iwl5000_apm_reset(struct iwl_priv *priv) -{ - int ret = 0; - - iwl_apm_stop_master(priv); - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - - udelay(10); - - - /* FIXME: put here L1A -L0S w/a */ - - if (priv->cfg->need_pll_cfg) - iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); - - /* set "initialization complete" bit to move adapter - * D0U* --> D0A* state */ - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret < 0) { - IWL_DEBUG_INFO(priv, "Failed to init the card\n"); - goto out; - } - - /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); - - udelay(20); - - /* disable L1-Active */ - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); -out: - - return ret; -} - - /* NIC configuration for 5000 series */ void iwl5000_nic_config(struct iwl_priv *priv) { @@ -1522,7 +1479,6 @@ struct iwl_lib_ops iwl5000_lib = { .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, - .reset = iwl5000_apm_reset, .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -1574,7 +1530,6 @@ static struct iwl_lib_ops iwl5150_lib = { .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, - .reset = iwl5000_apm_reset, .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index d1f0b0b4ad0c..46af74b86a83 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -192,7 +192,6 @@ static struct iwl_lib_ops iwl6000_lib = { .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, - .reset = iwl5000_apm_reset, .stop = iwl_apm_stop, .config = iwl6000_nic_config, .set_pwr_src = iwl_set_pwr_src, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 6688b6944200..447eb64e1f69 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -109,7 +109,6 @@ struct iwl_hcmd_utils_ops { struct iwl_apm_ops { int (*init)(struct iwl_priv *priv); - int (*reset)(struct iwl_priv *priv); void (*stop)(struct iwl_priv *priv); void (*config)(struct iwl_priv *priv); int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 72946c144be7..9da0b0343b99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -86,7 +86,6 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, extern int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp); extern int iwl5000_apm_init(struct iwl_priv *priv); -extern int iwl5000_apm_reset(struct iwl_priv *priv); extern void iwl5000_nic_config(struct iwl_priv *priv); extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv); extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, -- cgit v1.2.3 From bd35f150823c21000f4c0f029abb258bc1ae3b5f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 9 Oct 2009 13:20:23 -0700 Subject: iwlwifi: remove duplicated/unused definition "IWL_CMD_QUEUE_NUM" is being defined in multiple places and used by all the devices. move it to iwl-dev.h file and shared by all the devices. Remove "IWL_CMD_FIFO_NUM", replaced by "IWL49_CMD_FIFO_NUM" and IWL50_CMD_FIFO_NUM" Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 3 --- drivers/net/wireless/iwlwifi/iwl-dev.h | 6 ++++++ 3 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 16772780c5b0..ccdac69838dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -71,12 +71,6 @@ #include "iwl-eeprom.h" -/* - * uCode queue management definitions ... - * Queue #4 is the command queue for 3945 and 4965. - */ -#define IWL_CMD_QUEUE_NUM 4 - /* Time constants */ #define SHORT_SLOT_TIME 9 #define LONG_SLOT_TIME 20 diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index b34322a32458..c606366b582c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -76,12 +76,9 @@ /* * uCode queue management definitions ... - * Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4. * The first queue used for block-ack aggregation is #7 (4965 only). * All block-ack aggregation queues should map to Tx DMA/FIFO channel 7. */ -#define IWL_CMD_QUEUE_NUM 4 -#define IWL_CMD_FIFO_NUM 4 #define IWL49_FIRST_AMPDU_QUEUE 7 /* Time constants */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9da0b0343b99..394402afaa57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -323,6 +323,12 @@ struct iwl_channel_info { * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */ #define IWL_MIN_NUM_QUEUES 10 +/* + * uCode queue management definitions ... + * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00. + */ +#define IWL_CMD_QUEUE_NUM 4 + /* Power management (not Tx power) structures */ enum iwl_pwr_src { -- cgit v1.2.3 From 55036d6602679fb88dd7b1c19bb7203a0213b684 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 9 Oct 2009 13:20:24 -0700 Subject: iwlwifi: additional items in sensitivity range table Add more items to sensitivity range table to avoid using hardcoded values. Initialize the table per device since unique per device information is required to perform sensitivity calibration. additional items in sensitivity range table: .barker_corr_th_min: Barker correlation threshold minimum .barker_corr_th_min_mrc: Barker correlation threshold minimum for MRC .nrg_th_cca: Energy threshold for Clear Channel Assessment Barker codes are a technique used in WLAN encoding for transmission. MRC is "Maximal Ratio Combining", a technique for optimally combining the signals from 2 or more receivers to achieve a better signal. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-5000.c | 8 ++++++++ drivers/net/wireless/iwlwifi/iwl-6000.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-calib.c | 9 ++++++--- drivers/net/wireless/iwlwifi/iwl-commands.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-dev.h | 8 ++++++++ 6 files changed, 30 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 782a36198f38..966858587e25 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -678,6 +678,10 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = { .nrg_th_cck = 100, .nrg_th_ofdm = 100, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, }; static void iwl4965_set_ct_threshold(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 33b38aa0d8c3..a9d1aa3ad57b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -329,6 +329,10 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = { .auto_corr_max_cck_mrc = 400, .nrg_th_cck = 95, .nrg_th_ofdm = 95, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, }; static struct iwl_sensitivity_ranges iwl5150_sensitivity = { @@ -351,6 +355,10 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = { .auto_corr_max_cck_mrc = 400, .nrg_th_cck = 95, .nrg_th_ofdm = 95, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, }; const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 46af74b86a83..dda1dd6ed40a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -121,6 +121,10 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { .auto_corr_max_cck_mrc = 310, .nrg_th_cck = 97, .nrg_th_ofdm = 100, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, }; static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 69a80d7c2e44..1f801eb9fbff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -447,11 +447,11 @@ static int iwl_sensitivity_write(struct iwl_priv *priv) cpu_to_le16((u16)data->nrg_th_ofdm); cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] = - cpu_to_le16(190); + cpu_to_le16(data->barker_corr_th_min); cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] = - cpu_to_le16(390); + cpu_to_le16(data->barker_corr_th_min_mrc); cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] = - cpu_to_le16(62); + cpu_to_le16(data->nrg_th_cca); IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n", data->auto_corr_ofdm, data->auto_corr_ofdm_mrc, @@ -524,6 +524,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv) data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc; data->nrg_th_cck = ranges->nrg_th_cck; data->nrg_th_ofdm = ranges->nrg_th_ofdm; + data->barker_corr_th_min = ranges->barker_corr_th_min; + data->barker_corr_th_min_mrc = ranges->barker_corr_th_min_mrc; + data->nrg_th_cca = ranges->nrg_th_cca; data->last_bad_plcp_cnt_ofdm = 0; data->last_fa_cnt_ofdm = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index ba3e4c837d87..2e8a55ed7de5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3247,12 +3247,6 @@ struct iwl_missed_beacon_notif { * Lower values mean higher energy; this means making sure that the value * in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy". * - * Driver should set the following entries to fixed values: - * - * HD_MIN_ENERGY_OFDM_DET_INDEX 100 - * HD_BARKER_CORR_TH_ADD_MIN_INDEX 190 - * HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX 390 - * HD_OFDM_ENERGY_TH_IN_INDEX 62 */ /* diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 394402afaa57..c1b07e2045e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -629,6 +629,10 @@ struct iwl_sensitivity_ranges { u16 auto_corr_max_cck_mrc; u16 auto_corr_min_cck; u16 auto_corr_min_cck_mrc; + + u16 barker_corr_th_min; + u16 barker_corr_th_min_mrc; + u16 nrg_th_cca; }; @@ -850,6 +854,10 @@ struct iwl_sensitivity_data { s32 nrg_auto_corr_silence_diff; u32 num_in_cck_no_fa; u32 nrg_th_ofdm; + + u16 barker_corr_th_min; + u16 barker_corr_th_min_mrc; + u16 nrg_th_cca; }; /* Chain noise (differential Rx gain) calib data */ -- cgit v1.2.3 From 1a34c043802a213e719420ece395cf25c85cc7c5 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 9 Oct 2009 13:20:25 -0700 Subject: iwlwifi: fix userspace setting of sleep_level_override The sleep_level_override debugfs file is used by the user to request a static power index instead of the dynamic sleep values. Users are expected to provide value from 1 to 5 as an index or -1 to disable it. The problem at the moment is that users can also provide 0 to this file which, together with the value 1, is translated to index 1. This is confusing and even more so when users write 0 to sleep_level_override and then read 1 from it afterwards. Modify checking to treat 0 as invalid. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 1794b9c4e6ac..aa62357c9151 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -801,7 +801,9 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, * valid here. However, let's not confuse them and present * IWL_POWER_INDEX_1 as "1", not "0". */ - if (value > 0) + if (value == 0) + return -EINVAL; + else if (value > 0) value -= 1; if (value != -1 && (value < 0 || value >= IWL_POWER_NUM)) -- cgit v1.2.3 From 743cdf1b65656faf1e6f1f74278c52b89a0b7360 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:26 -0700 Subject: iwl3945: streamline iwl3945_rfkill_poll() iwl3945_rfkill_poll() has been silently calling wiphy_rfkill_set_hw_state() every 2 seconds, regardless of whether hardware RF KILL switch changed state. Call wiphy_rfkill_set_hw_state() only when RFKILL switch changes. Add IWL_DEBUG_RF_KILL log message and documentation. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index ab4c4bae7600..2406b73e9093 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2717,19 +2717,34 @@ static void iwl3945_bg_alive_start(struct work_struct *data) mutex_unlock(&priv->mutex); } +/* + * 3945 cannot interrupt driver when hardware rf kill switch toggles; + * driver must poll CSR_GP_CNTRL_REG register for change. This register + * *is* readable even when device has been SW_RESET into low power mode + * (e.g. during RF KILL). + */ static void iwl3945_rfkill_poll(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, rfkill_poll.work); + bool old_rfkill = test_bit(STATUS_RF_KILL_HW, &priv->status); + bool new_rfkill = !(iwl_read32(priv, CSR_GP_CNTRL) + & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); - if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) - clear_bit(STATUS_RF_KILL_HW, &priv->status); - else - set_bit(STATUS_RF_KILL_HW, &priv->status); + if (new_rfkill != old_rfkill) { + if (new_rfkill) + set_bit(STATUS_RF_KILL_HW, &priv->status); + else + clear_bit(STATUS_RF_KILL_HW, &priv->status); - wiphy_rfkill_set_hw_state(priv->hw->wiphy, - test_bit(STATUS_RF_KILL_HW, &priv->status)); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, new_rfkill); + + IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", + new_rfkill ? "disable radio" : "enable radio"); + } + /* Keep this running, even if radio now enabled. This will be + * cancelled in mac_start() if system decides to start again */ queue_delayed_work(priv->workqueue, &priv->rfkill_poll, round_jiffies_relative(2 * HZ)); -- cgit v1.2.3 From 008a9e3e3c37abd7f56d2478fe92d5874de3630a Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:27 -0700 Subject: iwl3945: move iwl_power_initialize() iwl_power_initialize() initializes driver data (not device hardware), and does not need to execute more than once (when the driver initializes). Therefore, it does not belong in iwl3945_apm_init(), which initializes hardware, and may run more than once. Move it to iwl3945_pci_probe(), where it will run only once. This agrees with similar placement in iwl-agn.c's iwl_pci_probe(), although placement under "services" seemed more appropriate than under "mac80211". Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 -- drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index f8ce96c94c6b..4e15a8e20d09 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -991,8 +991,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv) { int ret; - iwl_power_initialize(priv); - /* Configure chip clock phase-lock-loop */ iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2406b73e9093..e0e566c932c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4064,6 +4064,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e &priv->bands[IEEE80211_BAND_2GHZ].channels[5]); iwl3945_setup_deferred_work(priv); iwl3945_setup_rx_handlers(priv); + iwl_power_initialize(priv); /********************************* * 8. Setup and Register mac80211 -- cgit v1.2.3 From 88804e2b33b6ab3974ff2330cd045ca53d6750c5 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 9 Oct 2009 13:20:28 -0700 Subject: iwlwifi: dynamic allocate tx queue structure Instead of always allocate the max number of tx queue structure, use dynamic allocation based on the number of queues in device configuration. With these changes, device does not have to allocate more memory than the h/w can support. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 4 +++ drivers/net/wireless/iwlwifi/iwl-3945.c | 23 +++++++++++----- drivers/net/wireless/iwlwifi/iwl-4965.c | 33 ++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-5000.c | 42 ++++++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-6000.c | 36 ++++++++++++++++++------- drivers/net/wireless/iwlwifi/iwl-core.c | 21 +++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 5 +++- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 12 +++++++-- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +-- drivers/net/wireless/iwlwifi/iwl-tx.c | 22 ++++++++++----- drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 - 11 files changed, 144 insertions(+), 59 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 1fc38142a491..a00f947bd59c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -158,6 +158,8 @@ struct iwl_cfg iwl1000_bgn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_1000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, @@ -179,6 +181,8 @@ struct iwl_cfg iwl1000_bg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_1000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 4e15a8e20d09..314cae773646 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -958,6 +958,11 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) iwl3945_hw_txq_ctx_free(priv); + /* allocate tx queue structure */ + rc = iwl_alloc_txq_mem(priv); + if (rc) + return rc; + /* Tx CMD queue */ rc = iwl3945_tx_reset(priv); if (rc) @@ -1170,12 +1175,16 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv) int txq_id; /* Tx queues */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - if (txq_id == IWL_CMD_QUEUE_NUM) - iwl_cmd_queue_free(priv); - else - iwl_tx_queue_free(priv, txq_id); + if (priv->txq) + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; + txq_id++) + if (txq_id == IWL_CMD_QUEUE_NUM) + iwl_cmd_queue_free(priv); + else + iwl_tx_queue_free(priv, txq_id); + /* free tx queue structure */ + iwl_free_txq_mem(priv); } void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) @@ -2503,7 +2512,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) } /* Assign number of Usable TX queues */ - priv->hw_params.max_txq_num = IWL39_NUM_QUEUES; + priv->hw_params.max_txq_num = priv->cfg->num_of_queues; priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; @@ -2838,6 +2847,7 @@ static struct iwl_cfg iwl3945_bg_cfg = { .eeprom_size = IWL3945_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, + .num_of_queues = IWL39_NUM_QUEUES, .mod_params = &iwl3945_mod_params, .use_isr_legacy = true, .ht_greenfield_support = false, @@ -2853,6 +2863,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { .eeprom_size = IWL3945_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, + .num_of_queues = IWL39_NUM_QUEUES, .mod_params = &iwl3945_mod_params, .use_isr_legacy = true, .ht_greenfield_support = false, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 966858587e25..c9d90169ab1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -62,8 +62,6 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv); /* module parameters */ static struct iwl_mod_params iwl4965_mod_params = { - .num_of_queues = IWL49_NUM_QUEUES, - .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, .amsdu_size_8K = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -698,19 +696,16 @@ static void iwl4965_set_ct_threshold(struct iwl_priv *priv) */ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) { + if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && + priv->cfg->mod_params->num_of_queues <= IWL49_NUM_QUEUES) + priv->cfg->num_of_queues = + priv->cfg->mod_params->num_of_queues; - if ((priv->cfg->mod_params->num_of_queues > IWL49_NUM_QUEUES) || - (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { - IWL_ERR(priv, - "invalid queues_num, should be between %d and %d\n", - IWL_MIN_NUM_QUEUES, IWL49_NUM_QUEUES); - return -EINVAL; - } - - priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->num_of_queues; priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM; priv->hw_params.scd_bc_tbls_size = - IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl); + priv->cfg->num_of_queues * + sizeof(struct iwl4965_scd_bc_tbl); priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.max_stations = IWL4965_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; @@ -1739,11 +1734,13 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || - (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { + (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues + <= txq_id)) { IWL_WARN(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWL49_FIRST_AMPDU_QUEUE, - IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1); + IWL49_FIRST_AMPDU_QUEUE + + priv->cfg->num_of_ampdu_queues - 1); return -EINVAL; } @@ -1804,11 +1801,13 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, u16 ra_tid; if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || - (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { + (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues + <= txq_id)) { IWL_WARN(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWL49_FIRST_AMPDU_QUEUE, - IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1); + IWL49_FIRST_AMPDU_QUEUE + + priv->cfg->num_of_ampdu_queues - 1); return -EINVAL; } @@ -2286,6 +2285,8 @@ struct iwl_cfg iwl4965_agn_cfg = { .eeprom_ver = EEPROM_4965_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, + .num_of_queues = IWL49_NUM_QUEUES, + .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, .mod_params = &iwl4965_mod_params, .use_isr_legacy = true, .ht_greenfield_support = false, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a9d1aa3ad57b..ab5b9d8d66be 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -749,18 +749,16 @@ int iwl5000_alive_notify(struct iwl_priv *priv) int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { - if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || - (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { - IWL_ERR(priv, - "invalid queues_num, should be between %d and %d\n", - IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES); - return -EINVAL; - } + if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && + priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES) + priv->cfg->num_of_queues = + priv->cfg->mod_params->num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; priv->hw_params.scd_bc_tbls_size = - IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); + priv->cfg->num_of_queues * + sizeof(struct iwl5000_scd_bc_tbl); priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; @@ -912,11 +910,13 @@ int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, u16 ra_tid; if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || - (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { + (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues + <= txq_id)) { IWL_WARN(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWL50_FIRST_AMPDU_QUEUE, - IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1); + IWL50_FIRST_AMPDU_QUEUE + + priv->cfg->num_of_ampdu_queues - 1); return -EINVAL; } @@ -970,11 +970,13 @@ int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || - (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { + (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues + <= txq_id)) { IWL_ERR(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWL50_FIRST_AMPDU_QUEUE, - IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1); + IWL50_FIRST_AMPDU_QUEUE + + priv->cfg->num_of_ampdu_queues - 1); return -EINVAL; } @@ -1584,8 +1586,6 @@ static struct iwl_ops iwl5150_ops = { }; struct iwl_mod_params iwl50_mod_params = { - .num_of_queues = IWL50_NUM_QUEUES, - .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .amsdu_size_8K = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -1602,6 +1602,8 @@ struct iwl_cfg iwl5300_agn_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, @@ -1621,6 +1623,8 @@ struct iwl_cfg iwl5100_bg_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, @@ -1640,6 +1644,8 @@ struct iwl_cfg iwl5100_abg_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, @@ -1659,6 +1665,8 @@ struct iwl_cfg iwl5100_agn_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, @@ -1678,6 +1686,8 @@ struct iwl_cfg iwl5350_agn_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, @@ -1697,6 +1707,8 @@ struct iwl_cfg iwl5150_agn_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index dda1dd6ed40a..bdc1c74b6820 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -129,18 +129,16 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) { - if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || - (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { - IWL_ERR(priv, - "invalid queues_num, should be between %d and %d\n", - IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES); - return -EINVAL; - } + if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && + priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES) + priv->cfg->num_of_queues = + priv->cfg->mod_params->num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; priv->hw_params.scd_bc_tbls_size = - IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); + priv->cfg->num_of_queues * + sizeof(struct iwl5000_scd_bc_tbl); priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; @@ -248,6 +246,8 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, @@ -272,6 +272,8 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, @@ -295,6 +297,8 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, @@ -321,6 +325,8 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, @@ -345,6 +351,8 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, @@ -368,6 +376,8 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, @@ -391,6 +401,8 @@ struct iwl_cfg iwl6050_2agn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, @@ -415,6 +427,8 @@ struct iwl_cfg iwl6050_2abg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, @@ -438,6 +452,8 @@ struct iwl_cfg iwl6000_3agn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, @@ -462,6 +478,8 @@ struct iwl_cfg iwl6050_3agn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index dc7fd87bed98..c40c7e2dacf8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2826,6 +2826,27 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) } EXPORT_SYMBOL(iwl_mac_reset_tsf); +int iwl_alloc_txq_mem(struct iwl_priv *priv) +{ + if (!priv->txq) + priv->txq = kzalloc( + sizeof(struct iwl_tx_queue) * priv->cfg->num_of_queues, + GFP_KERNEL); + if (!priv->txq) { + IWL_ERR(priv, "Not enough memory for txq \n"); + return -ENOMEM; + } + return 0; +} +EXPORT_SYMBOL(iwl_alloc_txq_mem); + +void iwl_free_txq_mem(struct iwl_priv *priv) +{ + kfree(priv->txq); + priv->txq = NULL; +} +EXPORT_SYMBOL(iwl_free_txq_mem); + #ifdef CONFIG_IWLWIFI_DEBUGFS #define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 447eb64e1f69..3679c2ced04d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -204,7 +204,6 @@ struct iwl_mod_params { int sw_crypto; /* def: 0 = using hardware encryption */ int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ - int num_of_ampdu_queues;/* def: HW dependent */ int disable_11n; /* def: 0 = 11n capabilities enabled */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ @@ -257,6 +256,8 @@ struct iwl_cfg { int eeprom_size; u16 eeprom_ver; u16 eeprom_calib_ver; + int num_of_queues; /* def: HW dependent */ + int num_of_ampdu_queues;/* def: HW dependent */ const struct iwl_ops *ops; const struct iwl_mod_params *mod_params; u8 valid_tx_ant; @@ -326,6 +327,8 @@ 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); +int iwl_alloc_txq_mem(struct iwl_priv *priv); +void iwl_free_txq_mem(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_alloc_traffic_mem(struct iwl_priv *priv); void iwl_free_traffic_mem(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index aa62357c9151..028d4bf8dcd8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -884,10 +884,14 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, 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; + (priv->cfg->num_of_queues * 32 * 8) + 400; const u8 *ptr; ssize_t ret; + if (!priv->txq) { + IWL_ERR(priv, "txq not ready\n"); + return -EAGAIN; + } buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) { IWL_ERR(priv, "Can not allocate buffer\n"); @@ -979,8 +983,12 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, int pos = 0; int cnt; int ret; - const size_t bufsz = sizeof(char) * 60 * IWL_MAX_NUM_QUEUES; + const size_t bufsz = sizeof(char) * 60 * priv->cfg->num_of_queues; + if (!priv->txq) { + IWL_ERR(priv, "txq not ready\n"); + return -EAGAIN; + } buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c1b07e2045e6..6d7c2350d8c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -974,8 +974,6 @@ struct traffic_stats { }; #endif -#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ - struct iwl_priv { /* ieee device used by generic ieee processing code */ @@ -1103,7 +1101,7 @@ struct iwl_priv { /* Rx and Tx DMA processing queues */ struct iwl_rx_queue rxq; - struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES]; + struct iwl_tx_queue *txq; unsigned long txq_ctx_active_msk; struct iwl_dma_ptr kw; /* keep warm address */ struct iwl_dma_ptr scd_bc_tbls; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index c832ba085dba..625da63d01ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -405,15 +405,19 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv) int txq_id; /* Tx queues */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - if (txq_id == IWL_CMD_QUEUE_NUM) - iwl_cmd_queue_free(priv); - else - iwl_tx_queue_free(priv, txq_id); - + if (priv->txq) + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; + txq_id++) + if (txq_id == IWL_CMD_QUEUE_NUM) + iwl_cmd_queue_free(priv); + else + iwl_tx_queue_free(priv, txq_id); iwl_free_dma_ptr(priv, &priv->kw); iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); + + /* free tx queue structure */ + iwl_free_txq_mem(priv); } EXPORT_SYMBOL(iwl_hw_txq_ctx_free); @@ -445,6 +449,12 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) IWL_ERR(priv, "Keep Warm allocation failed\n"); goto error_kw; } + + /* allocate tx queue structure */ + ret = iwl_alloc_txq_mem(priv); + if (ret) + goto error; + spin_lock_irqsave(&priv->lock, flags); /* Turn off all Tx DMA fifos */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e0e566c932c5..66da441fe366 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -88,7 +88,6 @@ MODULE_LICENSE("GPL"); /* module parameters */ struct iwl_mod_params iwl3945_mod_params = { - .num_of_queues = IWL39_NUM_QUEUES, /* Not used */ .sw_crypto = 1, .restart_fw = 1, /* the rest are 0 by default */ -- cgit v1.2.3 From 92a35bda792cf9295b1d399f7c937d4560292b1e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 9 Oct 2009 13:20:29 -0700 Subject: iwlwifi: showing accumulative ucode statistics counters Adding accumulative statistics counters in iwlwifi driver. Statistics counters are reported by uCode every beacon interval; but can be reset by uCode when needed. The accumulative statistics counters is maintained by driver to keep track of the history of all the counters. Update the ucode stats files in debugfs to display both latest and accumulative counters. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 - drivers/net/wireless/iwlwifi/iwl-debugfs.c | 629 ++++++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 41 ++ 4 files changed, 447 insertions(+), 229 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 314cae773646..cee03e7fc2da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -361,8 +361,6 @@ void iwl3945_hw_rx_statistics(struct iwl_priv *priv, memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39)); iwl_leds_background(priv); - - priv->last_statistics_time = jiffies; } /****************************************************************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 028d4bf8dcd8..2cd11ba96370 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1079,10 +1079,10 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, 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; + struct statistics_rx_phy *ofdm, *accum_ofdm; + struct statistics_rx_phy *cck, *accum_cck; + struct statistics_rx_non_phy *general, *accum_general; + struct statistics_rx_ht_phy *ht, *accum_ht; if (!iwl_is_alive(priv)) return -EAGAIN; @@ -1111,155 +1111,268 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, cck = &priv->statistics.rx.cck; general = &priv->statistics.rx.general; ht = &priv->statistics.rx.ofdm_ht; + accum_ofdm = &priv->accum_statistics.rx.ofdm; + accum_cck = &priv->accum_statistics.rx.cck; + accum_general = &priv->accum_statistics.rx.general; + accum_ht = &priv->accum_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, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->ina_cnt), accum_ofdm->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + "overrun_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->overrun_err), + accum_ofdm->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + "early_overrun_err:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->early_overrun_err), + accum_ofdm->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->crc32_good), + accum_ofdm->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + "false_alarm_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->false_alarm_cnt), + accum_ofdm->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_sync_err_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->fina_sync_err_cnt), + accum_ofdm->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sfd_timeout:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->sfd_timeout), + accum_ofdm->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_timeout:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->fina_timeout), + accum_ofdm->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "unresponded_rts:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->unresponded_rts), + accum_ofdm->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->rxe_frame_limit_overrun), + accum_ofdm->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ack_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->sent_ack_cnt), + accum_ofdm->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_cts_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->sent_cts_cnt), + accum_ofdm->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ba_rsp_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->sent_ba_rsp_cnt), + accum_ofdm->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "dsp_self_kill:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->dsp_self_kill), + accum_ofdm->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + "mh_format_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->mh_format_err), + accum_ofdm->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + "re_acq_main_rssi_sum:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->re_acq_main_rssi_sum), + accum_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, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->plcp_err), accum_cck->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->crc32_err), accum_cck->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + "overrun_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->overrun_err), + accum_cck->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + "early_overrun_err:\t%u\t\t\t%u\n", + le32_to_cpu(cck->early_overrun_err), + accum_cck->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->crc32_good), accum_cck->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + "false_alarm_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(cck->false_alarm_cnt), + accum_cck->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_sync_err_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(cck->fina_sync_err_cnt), + accum_cck->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sfd_timeout:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->sfd_timeout), + accum_cck->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_timeout:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->fina_timeout), + accum_cck->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "unresponded_rts:\t%u\t\t\t%u\n", + le32_to_cpu(cck->unresponded_rts), + accum_cck->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n", + le32_to_cpu(cck->rxe_frame_limit_overrun), + accum_cck->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ack_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->sent_ack_cnt), + accum_cck->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_cts_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->sent_cts_cnt), + accum_cck->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ba_rsp_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(cck->sent_ba_rsp_cnt), + accum_cck->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "dsp_self_kill:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->dsp_self_kill), + accum_cck->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + "mh_format_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->mh_format_err), + accum_cck->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + "re_acq_main_rssi_sum:\t%u\t\t\t%u\n", + le32_to_cpu(cck->re_acq_main_rssi_sum), + accum_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, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->bogus_cts), + accum_general->bogus_cts); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->bogus_ack), + accum_general->bogus_ack); + pos += scnprintf(buf + pos, bufsz - pos, + "non_bssid_frames:\t%u\t\t\t%u\n", + le32_to_cpu(general->non_bssid_frames), + accum_general->non_bssid_frames); + pos += scnprintf(buf + pos, bufsz - pos, + "filtered_frames:\t%u\t\t\t%u\n", + le32_to_cpu(general->filtered_frames), + accum_general->filtered_frames); + pos += scnprintf(buf + pos, bufsz - pos, + "non_channel_beacons:\t%u\t\t\t%u\n", + le32_to_cpu(general->non_channel_beacons), + accum_general->non_channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + "channel_beacons:\t%u\t\t\t%u\n", + le32_to_cpu(general->channel_beacons), + accum_general->channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + "num_missed_bcon:\t%u\t\t\t%u\n", + le32_to_cpu(general->num_missed_bcon), + accum_general->num_missed_bcon); + pos += scnprintf(buf + pos, bufsz - pos, + "adc_rx_saturation_time:\t%u\t\t\t%u\n", + le32_to_cpu(general->adc_rx_saturation_time), + accum_general->adc_rx_saturation_time); + pos += scnprintf(buf + pos, bufsz - pos, + "ina_detect_search_tm:\t%u\t\t\t%u\n", + le32_to_cpu(general->ina_detection_search_time), + accum_general->ina_detection_search_time); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_silence_rssi_a:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_silence_rssi_a), + accum_general->beacon_silence_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_silence_rssi_b:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_silence_rssi_b), + accum_general->beacon_silence_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_silence_rssi_c:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_silence_rssi_c), + accum_general->beacon_silence_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + "interference_data_flag:\t%u\t\t\t%u\n", + le32_to_cpu(general->interference_data_flag), + accum_general->interference_data_flag); + pos += scnprintf(buf + pos, bufsz - pos, + "channel_load:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->channel_load), + accum_general->channel_load); + pos += scnprintf(buf + pos, bufsz - pos, + "dsp_false_alarms:\t%u\t\t\t%u\n", + le32_to_cpu(general->dsp_false_alarms), + accum_general->dsp_false_alarms); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_rssi_a:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_rssi_a), + accum_general->beacon_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_rssi_b:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_rssi_b), + accum_general->beacon_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_rssi_c:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_rssi_c), + accum_general->beacon_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_energy_a:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_energy_a), + accum_general->beacon_energy_a); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_energy_b:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_energy_b), + accum_general->beacon_energy_b); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_energy_c:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_energy_c), + accum_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)); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->plcp_err), accum_ht->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + "overrun_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->overrun_err), accum_ht->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + "early_overrun_err:\t%u\t\t\t%u\n", + le32_to_cpu(ht->early_overrun_err), + accum_ht->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->crc32_good), accum_ht->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->crc32_err), accum_ht->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + "mh_format_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->mh_format_err), + accum_ht->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + "agg_crc32_good:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->agg_crc32_good), + accum_ht->agg_crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + "agg_mpdu_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->agg_mpdu_cnt), + accum_ht->agg_mpdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -1275,7 +1388,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, char *buf; int bufsz = (sizeof(struct statistics_tx) * 24) + 250; ssize_t ret; - struct statistics_tx *tx; + struct statistics_tx *tx, *accum_tx; if (!iwl_is_alive(priv)) return -EAGAIN; @@ -1301,62 +1414,107 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, * might not reflect the current uCode activity */ tx = &priv->statistics.tx; + accum_tx = &priv->accum_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)); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "preamble:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->preamble_cnt), + accum_tx->preamble_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "rx_detected_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->rx_detected_cnt), + accum_tx->rx_detected_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "bt_prio_defer_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->bt_prio_defer_cnt), + accum_tx->bt_prio_defer_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "bt_prio_kill_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->bt_prio_kill_cnt), + accum_tx->bt_prio_kill_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "few_bytes_cnt:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->few_bytes_cnt), + accum_tx->few_bytes_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "cts_timeout:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "ack_timeout:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->ack_timeout), + accum_tx->ack_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "expected_ack_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->expected_ack_cnt), + accum_tx->expected_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "actual_ack_cnt:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->actual_ack_cnt), + accum_tx->actual_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "dump_msdu_cnt:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->dump_msdu_cnt), + accum_tx->dump_msdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "abort_nxt_frame_mismatch:" + "\t%u\t\t\t%u\n", + le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), + accum_tx->burst_abort_next_frame_mismatch_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "abort_missing_nxt_frame:" + "\t%u\t\t\t%u\n", + le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), + accum_tx->burst_abort_missing_next_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "cts_timeout_collision:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->cts_timeout_collision), + accum_tx->cts_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + "ack_ba_timeout_collision:\t%u\t\t\t%u\n", + le32_to_cpu(tx->ack_or_ba_timeout_collision), + accum_tx->ack_or_ba_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + "agg ba_timeout:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.ba_timeout), + accum_tx->agg.ba_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "agg ba_resched_frames:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.ba_reschedule_frames), + accum_tx->agg.ba_reschedule_frames); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_agg_frame:\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), + accum_tx->agg.scd_query_agg_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_no_agg:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.scd_query_no_agg), + accum_tx->agg.scd_query_no_agg); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_agg:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.scd_query_agg), + accum_tx->agg.scd_query_agg); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_mismatch:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.scd_query_mismatch), + accum_tx->agg.scd_query_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, + "agg frame_not_ready:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.frame_not_ready), + accum_tx->agg.frame_not_ready); + pos += scnprintf(buf + pos, bufsz - pos, + "agg underrun:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.underrun), + accum_tx->agg.underrun); + pos += scnprintf(buf + pos, bufsz - pos, + "agg bt_prio_kill:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.bt_prio_kill), + accum_tx->agg.bt_prio_kill); + pos += scnprintf(buf + pos, bufsz - pos, + "agg rx_ba_rsp_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.rx_ba_rsp_cnt), + accum_tx->agg.rx_ba_rsp_cnt); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -1372,9 +1530,9 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, 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; + struct statistics_general *general, *accum_general; + struct statistics_dbg *dbg, *accum_dbg; + struct statistics_div *div, *accum_div; if (!iwl_is_alive(priv)) return -EAGAIN; @@ -1402,34 +1560,53 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, general = &priv->statistics.general; dbg = &priv->statistics.general.dbg; div = &priv->statistics.general.div; + accum_general = &priv->accum_statistics.general; + accum_dbg = &priv->accum_statistics.general.dbg; + accum_div = &priv->accum_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", + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "temperature:\t\t\t%u\n", le32_to_cpu(general->temperature)); - pos += scnprintf(buf + pos, bufsz - pos, "temperature_m: %u\n", + pos += scnprintf(buf + pos, bufsz - pos, "temperature_m:\t\t\t%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", + pos += scnprintf(buf + pos, bufsz - pos, + "burst_check:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(dbg->burst_check), + accum_dbg->burst_check); + pos += scnprintf(buf + pos, bufsz - pos, + "burst_count:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(dbg->burst_count), + accum_dbg->burst_count); + pos += scnprintf(buf + pos, bufsz - pos, + "sleep_time:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(general->sleep_time), + accum_general->sleep_time); + pos += scnprintf(buf + pos, bufsz - pos, + "slots_out:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(general->slots_out), + accum_general->slots_out); + pos += scnprintf(buf + pos, bufsz - pos, + "slots_idle:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(general->slots_idle), + accum_general->slots_idle); + pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%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)); + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->tx_on_a), accum_div->tx_on_a); + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->tx_on_b), accum_div->tx_on_b); + pos += scnprintf(buf + pos, bufsz - pos, + "exec_time:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->exec_time), accum_div->exec_time); + pos += scnprintf(buf + pos, bufsz - pos, + "probe_time:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->probe_time), accum_div->probe_time); + pos += scnprintf(buf + pos, bufsz - pos, + "rx_enable_counter:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->rx_enable_counter), + accum_general->rx_enable_counter); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 6d7c2350d8c9..8d087f0455de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1124,7 +1124,9 @@ struct iwl_priv { struct iwl_tt_mgmt thermal_throttle; struct iwl_notif_statistics statistics; - unsigned long last_statistics_time; +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_notif_statistics accum_statistics; +#endif /* context information */ u16 rates_mask; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 493626bcd3ec..7ad327ef9cb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -548,6 +548,44 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv) priv->last_rx_noise); } +#ifdef CONFIG_IWLWIFI_DEBUG +/* + * based on the assumption of all statistics counter are in DWORD + * FIXME: This function is for debugging, do not deal with + * the case of counters roll-over. + */ +static void iwl_accumulative_statistics(struct iwl_priv *priv, + __le32 *stats) +{ + int i; + __le32 *prev_stats; + u32 *accum_stats; + + prev_stats = (__le32 *)&priv->statistics; + accum_stats = (u32 *)&priv->accum_statistics; + + for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics); + i += sizeof(__le32), stats++, prev_stats++, accum_stats++) + if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) + *accum_stats += (le32_to_cpu(*stats) - + le32_to_cpu(*prev_stats)); + + /* reset accumulative statistics for "no-counter" type statistics */ + priv->accum_statistics.general.temperature = + priv->statistics.general.temperature; + priv->accum_statistics.general.temperature_m = + priv->statistics.general.temperature_m; + priv->accum_statistics.general.ttl_timestamp = + priv->statistics.general.ttl_timestamp; + priv->accum_statistics.tx.tx_power.ant_a = + priv->statistics.tx.tx_power.ant_a; + priv->accum_statistics.tx.tx_power.ant_b = + priv->statistics.tx.tx_power.ant_b; + priv->accum_statistics.tx.tx_power.ant_c = + priv->statistics.tx.tx_power.ant_c; +} +#endif + #define REG_RECALIB_PERIOD (60) void iwl_rx_statistics(struct iwl_priv *priv, @@ -566,6 +604,9 @@ void iwl_rx_statistics(struct iwl_priv *priv, STATISTICS_REPLY_FLG_HT40_MODE_MSK) != (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); +#ifdef CONFIG_IWLWIFI_DEBUG + iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); +#endif memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); set_bit(STATUS_STATISTICS, &priv->status); -- cgit v1.2.3 From 37dc70fea870ced8fbd9ae786701529e7ce48f03 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 9 Oct 2009 13:20:30 -0700 Subject: iwlwifi/iwl3945: unify rts_tx_cmd_flag 3945 and 4965 share the functionality for setting RTS and CTS to the tx_cmd. Unify these functions and move the common functionality to core. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 1 + drivers/net/wireless/iwlwifi/iwl-4965.c | 14 +------------- drivers/net/wireless/iwlwifi/iwl-core.c | 17 +++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 9 +-------- 5 files changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index cee03e7fc2da..1372ce4a407c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2826,6 +2826,7 @@ static struct iwl_lib_ops iwl3945_lib = { static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { .get_hcmd_size = iwl3945_get_hcmd_size, .build_addsta_hcmd = iwl3945_build_addsta_hcmd, + .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag, }; static struct iwl_ops iwl3945_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index c9d90169ab1a..6d77039b4ed2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -484,18 +484,6 @@ static void iwl4965_gain_computation(struct iwl_priv *priv, data->beacon_count = 0; } -static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info, - __le32 *tx_flags) -{ - if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { - *tx_flags |= TX_CMD_FLG_RTS_MSK; - *tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - *tx_flags &= ~TX_CMD_FLG_RTS_MSK; - *tx_flags |= TX_CMD_FLG_CTS_MSK; - } -} - static void iwl4965_bg_txpower_work(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, @@ -2212,7 +2200,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .build_addsta_hcmd = iwl4965_build_addsta_hcmd, .chain_noise_reset = iwl4965_chain_noise_reset, .gain_computation = iwl4965_gain_computation, - .rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag, + .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag, .calc_rssi = iwl4965_calc_rssi, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c40c7e2dacf8..1e0021f9681c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -604,6 +604,23 @@ void iwlcore_free_geos(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_free_geos); +/* + * iwlcore_rts_tx_cmd_flag: Set rts/cts. 3945 and 4965 only share this + * function. + */ +void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info, + __le32 *tx_flags) +{ + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { + *tx_flags |= TX_CMD_FLG_RTS_MSK; + *tx_flags &= ~TX_CMD_FLG_CTS_MSK; + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + *tx_flags &= ~TX_CMD_FLG_RTS_MSK; + *tx_flags |= TX_CMD_FLG_CTS_MSK; + } +} +EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag); + static bool is_single_rx_stream(struct iwl_priv *priv) { return !priv->current_ht_config.is_ht || diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3679c2ced04d..cec673badf0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -329,6 +329,8 @@ int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, void iwl_mac_reset_tsf(struct ieee80211_hw *hw); int iwl_alloc_txq_mem(struct iwl_priv *priv); void iwl_free_txq_mem(struct iwl_priv *priv); +void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info, + __le32 *tx_flags); #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_alloc_traffic_mem(struct iwl_priv *priv); void iwl_free_traffic_mem(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 66da441fe366..f4d43531bfa4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -408,7 +408,6 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; __le32 tx_flags = tx->tx_flags; __le16 fc = hdr->frame_control; - u8 rc_flags = info->control.rates[0].flags; tx->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { @@ -435,13 +434,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - tx_flags |= TX_CMD_FLG_RTS_MSK; - tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx_flags |= TX_CMD_FLG_CTS_MSK; - } + priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags); if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; -- cgit v1.2.3 From 9744c91f91e9e467b38473a8b673324ae658ca88 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 9 Oct 2009 13:20:31 -0700 Subject: iwl3945: rename tx to tx_cmd Rename iwl3945_tx_cmd variable tx to tx_cmd for better readability. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 20 +++++------ drivers/net/wireless/iwlwifi/iwl3945-base.c | 54 ++++++++++++++--------------- 2 files changed, 37 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 1372ce4a407c..a6944bc53fec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -785,10 +785,10 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, u8 data_retry_limit; __le32 tx_flags; __le16 fc = hdr->frame_control; - struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; + struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload; rate = iwl3945_rates[rate_index].plcp; - tx_flags = tx->tx_flags; + tx_flags = tx_cmd->tx_flags; /* We need to figure out how to get the sta->supp_rates while * in this running context */ @@ -825,22 +825,22 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, } } - tx->rts_retry_limit = rts_retry_limit; - tx->data_retry_limit = data_retry_limit; - tx->rate = rate; - tx->tx_flags = tx_flags; + tx_cmd->rts_retry_limit = rts_retry_limit; + tx_cmd->data_retry_limit = data_retry_limit; + tx_cmd->rate = rate; + tx_cmd->tx_flags = tx_flags; /* OFDM */ - tx->supp_rates[0] = + tx_cmd->supp_rates[0] = ((rate_mask & IWL_OFDM_RATES_MASK) >> IWL_FIRST_OFDM_RATE) & 0xFF; /* CCK */ - tx->supp_rates[1] = (rate_mask & 0xF); + tx_cmd->supp_rates[1] = (rate_mask & 0xF); IWL_DEBUG_RATE(priv, "Tx sta id: %d, rate: %d (plcp), flags: 0x%4X " "cck/ofdm mask: 0x%x/0x%x\n", sta_id, - tx->rate, le32_to_cpu(tx->tx_flags), - tx->supp_rates[1], tx->supp_rates[0]); + tx_cmd->rate, le32_to_cpu(tx_cmd->tx_flags), + tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]); } u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f4d43531bfa4..03612b394591 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -365,13 +365,13 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct sk_buff *skb_frag, int sta_id) { - struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; + struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload; struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: - tx->sec_ctl = TX_CMD_SEC_CCM; - memcpy(tx->key, keyinfo->key, keyinfo->keylen); + tx_cmd->sec_ctl = TX_CMD_SEC_CCM; + memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen); IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n"); break; @@ -379,13 +379,13 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, break; case ALG_WEP: - tx->sec_ctl = TX_CMD_SEC_WEP | + tx_cmd->sec_ctl = TX_CMD_SEC_WEP | (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; if (keyinfo->keylen == 13) - tx->sec_ctl |= TX_CMD_SEC_KEY128; + tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; - memcpy(&tx->key[3], keyinfo->key, keyinfo->keylen); + memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen); IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption " "with key %d\n", info->control.hw_key->hw_key_idx); @@ -405,11 +405,11 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, u8 std_id) { - struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; - __le32 tx_flags = tx->tx_flags; + struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload; + __le32 tx_flags = tx_cmd->tx_flags; __le16 fc = hdr->frame_control; - tx->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { tx_flags |= TX_CMD_FLG_ACK_MSK; if (ieee80211_is_mgmt(fc)) @@ -422,13 +422,13 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - tx->sta_id = std_id; + tx_cmd->sta_id = std_id; if (ieee80211_has_morefrags(fc)) tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; if (ieee80211_is_data_qos(fc)) { u8 *qc = ieee80211_get_qos_ctl(hdr); - tx->tid_tspec = qc[0] & 0xf; + tx_cmd->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } else { tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; @@ -442,16 +442,16 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); if (ieee80211_is_mgmt(fc)) { if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) - tx->timeout.pm_frame_timeout = cpu_to_le16(3); + tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3); else - tx->timeout.pm_frame_timeout = cpu_to_le16(2); + tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2); } else { - tx->timeout.pm_frame_timeout = 0; + tx_cmd->timeout.pm_frame_timeout = 0; } - tx->driver_txop = 0; - tx->tx_flags = tx_flags; - tx->next_frame_len = 0; + tx_cmd->driver_txop = 0; + tx_cmd->tx_flags = tx_flags; + tx_cmd->next_frame_len = 0; } /* @@ -461,7 +461,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct iwl3945_tx_cmd *tx; + struct iwl3945_tx_cmd *tx_cmd; struct iwl_tx_queue *txq = NULL; struct iwl_queue *q = NULL; struct iwl_device_cmd *out_cmd; @@ -560,9 +560,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Init first empty entry in queue's array of Tx/cmd buffers */ out_cmd = txq->cmd[idx]; out_meta = &txq->meta[idx]; - tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload; + tx_cmd = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); - memset(tx, 0, sizeof(*tx)); + memset(tx_cmd, 0, sizeof(*tx_cmd)); /* * Set up the Tx-command (not MAC!) header. @@ -575,7 +575,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) INDEX_TO_SEQ(q->write_ptr))); /* Copy MAC header from skb into command buffer */ - memcpy(tx->hdr, hdr, hdr_len); + memcpy(tx_cmd->hdr, hdr, hdr_len); if (info->control.hw_key) @@ -589,12 +589,12 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Total # bytes to be transmitted */ len = (u16)skb->len; - tx->len = cpu_to_le16(len); + tx_cmd->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; + tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; + tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; @@ -607,9 +607,9 @@ 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(priv, IWL_DL_TX, tx, sizeof(*tx)); - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr, + IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags)); + iwl_print_hex_dump(priv, IWL_DL_TX, tx_cmd, sizeof(*tx_cmd)); + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, ieee80211_hdrlen(fc)); /* -- cgit v1.2.3 From 1f0436f4702b7cdda22a38689cc1903822694a17 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 9 Oct 2009 13:20:32 -0700 Subject: iwlwifi/iwl3945: remove data_retry_limit Remove the ununsed variable data_retry_limit from priv. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 3 --- drivers/net/wireless/iwlwifi/iwl-core.c | 1 - drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-tx.c | 4 +--- drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 - 5 files changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index a6944bc53fec..eb874e08ba53 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -806,9 +806,6 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, } else data_retry_limit = IWL_DEFAULT_TX_RETRY; - if (priv->data_retry_limit != -1) - data_retry_limit = priv->data_retry_limit; - if (ieee80211_is_mgmt(fc)) { switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { case cpu_to_le16(IEEE80211_STYPE_AUTH): diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1e0021f9681c..2ae168af0f2c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1524,7 +1524,6 @@ int iwl_init_drv(struct iwl_priv *priv) /* Clear the driver's (not device's) station table */ iwl_clear_stations_table(priv); - priv->data_retry_limit = -1; priv->ieee_channels = NULL; priv->ieee_rates = NULL; priv->band = IEEE80211_BAND_2GHZ; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 8d087f0455de..451aa65b1a56 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1092,7 +1092,6 @@ struct iwl_priv { u8 last_phy_res[100]; /* Rate scaling data */ - s8 data_retry_limit; u8 retry_rate; wait_queue_head_t wait_command_queue; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 625da63d01ee..d0bd7cd024ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -591,9 +591,7 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, u8 rate_plcp; /* 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)) + if (ieee80211_is_probe_resp(fc)) data_retry_limit = 3; else data_retry_limit = IWL_DEFAULT_TX_RETRY; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 03612b394591..515f29b8a7a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3797,7 +3797,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) /* Clear the driver's (not device's) station table */ iwl_clear_stations_table(priv); - priv->data_retry_limit = -1; priv->ieee_channels = NULL; priv->ieee_rates = NULL; priv->band = IEEE80211_BAND_2GHZ; -- cgit v1.2.3 From 768db9829d0d45d57204714f18b54f7fc0561ddf Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 9 Oct 2009 13:20:33 -0700 Subject: iwl3945: rearrange the code. Rearrange the code and groups setting of retry_limit and data_retry_limits code together. Make 'data_retry_limit' setting similar to iwlwifi for better readability. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index eb874e08ba53..8012381d3717 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -794,17 +794,22 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, * in this running context */ rate_mask = IWL_RATES_MASK; + + /* Set retry limit on DATA packets and Probe Responses*/ + 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; + if (tx_id >= IWL_CMD_QUEUE_NUM) rts_retry_limit = 3; else rts_retry_limit = 7; - 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; + if (data_retry_limit < rts_retry_limit) + rts_retry_limit = data_retry_limit; + tx_cmd->rts_retry_limit = rts_retry_limit; if (ieee80211_is_mgmt(fc)) { switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { @@ -822,8 +827,6 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, } } - tx_cmd->rts_retry_limit = rts_retry_limit; - tx_cmd->data_retry_limit = data_retry_limit; tx_cmd->rate = rate; tx_cmd->tx_flags = tx_flags; -- cgit v1.2.3 From e57f14895bf6bc7f16df760963427ac6ee6ff7e1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 9 Oct 2009 13:20:34 -0700 Subject: iwlwifi: update channel switch command API Channel switch host command has different data structure for different devices. Adding additional structures to support 5000 and 6000 NICs. unlike 4965, starting with 5000 series, the tx power is managed by uCode, there is no tx power db information need to be passing from driver to uCode; but the space needs to be reserved to match uCode expection. 1000 NIC do not support channel switch operation since it is 'bgn' device, there is no need to have data structure defined for it. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 47 ++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 2e8a55ed7de5..cc4e9122709e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -353,6 +353,9 @@ struct iwl3945_power_per_rate { #define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 #define POWER_TABLE_CCK_ENTRY 32 +#define IWL_PWR_NUM_HT_OFDM_ENTRIES 24 +#define IWL_PWR_CCK_ENTRIES 2 + /** * union iwl4965_tx_power_dual_stream * @@ -803,7 +806,7 @@ struct iwl3945_channel_switch_cmd { struct iwl3945_power_per_rate power[IWL_MAX_RATES]; } __attribute__ ((packed)); -struct iwl_channel_switch_cmd { +struct iwl4965_channel_switch_cmd { u8 band; u8 expect_beacon; __le16 channel; @@ -813,6 +816,48 @@ struct iwl_channel_switch_cmd { struct iwl4965_tx_power_db tx_power; } __attribute__ ((packed)); +/** + * struct iwl5000_channel_switch_cmd + * @band: 0- 5.2GHz, 1- 2.4GHz + * @expect_beacon: 0- resume transmits after channel switch + * 1- wait for beacon to resume transmits + * @channel: new channel number + * @rxon_flags: Rx on flags + * @rxon_filter_flags: filtering parameters + * @switch_time: switch time in extended beacon format + * @reserved: reserved bytes + */ +struct iwl5000_channel_switch_cmd { + u8 band; + u8 expect_beacon; + __le16 channel; + __le32 rxon_flags; + __le32 rxon_filter_flags; + __le32 switch_time; + __le32 reserved[2][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES]; +} __attribute__ ((packed)); + +/** + * struct iwl6000_channel_switch_cmd + * @band: 0- 5.2GHz, 1- 2.4GHz + * @expect_beacon: 0- resume transmits after channel switch + * 1- wait for beacon to resume transmits + * @channel: new channel number + * @rxon_flags: Rx on flags + * @rxon_filter_flags: filtering parameters + * @switch_time: switch time in extended beacon format + * @reserved: reserved bytes + */ +struct iwl6000_channel_switch_cmd { + u8 band; + u8 expect_beacon; + __le16 channel; + __le32 rxon_flags; + __le32 rxon_filter_flags; + __le32 switch_time; + __le32 reserved[3][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES]; +} __attribute__ ((packed)); + /* * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) */ -- cgit v1.2.3 From 2f301227a1ede57504694e1f64839839f5737cac Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 9 Oct 2009 17:19:45 +0800 Subject: iwlwifi: use paged Rx This switches the iwlwifi driver to use paged skb from linear skb for Rx buffer. So that it relieves some Rx buffer allocation pressure for the memory subsystem. Currently iwlwifi (4K for 3945) requests 8K bytes for Rx buffer. Due to the trailing skb_shared_info in the skb->data, alloc_skb() will do the next order allocation, which is 16K bytes. This is suboptimal and more likely to fail when the system is under memory usage pressure. Switching to paged Rx skb lets us allocate the RXB directly by alloc_pages(), so that only order 1 allocation is required. It also adjusts the area spin_lock (with IRQ disabled) protected in the tasklet because tasklet guarentees to run only on one CPU and the new unprotected code can be preempted by the IRQ handler. This saves us from spawning another workqueue to make skb_linearize/__pskb_pull_tail happy (which cannot be called in hard irq context). Finally, mac80211 doesn't support paged Rx yet. So we linearize the skb for all the management frames and software decryption or defragmentation required data frames before handed to mac80211. For all the other frames, we __pskb_pull_tail 64 bytes in the linear area of the skb for mac80211 to handle them properly. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 67 ++++++++++----- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-5000.c | 4 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 42 +++++----- drivers/net/wireless/iwlwifi/iwl-commands.h | 10 +++ drivers/net/wireless/iwlwifi/iwl-core.c | 13 ++- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 27 +++--- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 21 ++--- drivers/net/wireless/iwlwifi/iwl-rx.c | 122 +++++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-scan.c | 20 ++--- drivers/net/wireless/iwlwifi/iwl-spectrum.c | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 62 ++++++-------- drivers/net/wireless/iwlwifi/iwl-tx.c | 10 +-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 120 ++++++++++++++------------- 15 files changed, 284 insertions(+), 240 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8012381d3717..b188a026637a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -293,7 +293,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv, static void iwl3945_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); @@ -353,7 +353,7 @@ 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) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(struct iwl3945_notif_statistics), le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); @@ -543,14 +543,17 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, 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_packet *pkt = rxb_addr(rxb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); 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); + u16 len = le16_to_cpu(rx_hdr->len); + struct sk_buff *skb; + int ret; /* We received data from the HW, so stop the watchdog */ - if (unlikely((len + IWL39_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) { + if (unlikely(len + IWL39_RX_FRAME_SIZE > + PAGE_SIZE << priv->hw_params.rx_page_order)) { IWL_DEBUG_DROP(priv, "Corruption detected!\n"); return; } @@ -562,20 +565,45 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, return; } - skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt); - /* Set the size of the skb to the size of the frame */ - skb_put(rxb->skb, le16_to_cpu(rx_hdr->len)); + skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC); + if (!skb) { + IWL_ERR(priv, "alloc_skb failed\n"); + return; + } if (!iwl3945_mod_params.sw_crypto) iwl_set_decrypted_flag(priv, - (struct ieee80211_hdr *)rxb->skb->data, + (struct ieee80211_hdr *)rxb_addr(rxb), le32_to_cpu(rx_end->status), stats); + skb_add_rx_frag(skb, 0, rxb->page, + (void *)rx_hdr->payload - (void *)pkt, len); + + /* mac80211 currently doesn't support paged SKB. Convert it to + * linear SKB for management frame and data frame requires + * software decryption or software defragementation. */ + if (ieee80211_is_mgmt(hdr->frame_control) || + ieee80211_has_protected(hdr->frame_control) || + ieee80211_has_morefrags(hdr->frame_control) || + le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) + ret = skb_linearize(skb); + else + ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ? + 0 : -ENOMEM; + + if (ret) { + kfree_skb(skb); + goto out; + } + 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; + memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); + ieee80211_rx(priv->hw, skb); + + out: + priv->alloc_rxb_page--; + rxb->page = NULL; } #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) @@ -585,7 +613,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, { struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status; - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); @@ -1811,7 +1839,7 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) { int rc = 0; - struct iwl_rx_packet *res = NULL; + struct iwl_rx_packet *pkt; struct iwl3945_rxon_assoc_cmd rxon_assoc; struct iwl_host_cmd cmd = { .id = REPLY_RXON_ASSOC, @@ -1840,14 +1868,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.reply_skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); rc = -EIO; } - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.reply_skb); + priv->alloc_rxb_page--; + free_pages(cmd.reply_page, priv->hw_params.rx_page_order); return rc; } @@ -2513,8 +2541,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_txq_num = priv->cfg->num_of_queues; priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; - priv->hw_params.max_pkt_size = 2342; + priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_3K); priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; priv->hw_params.max_stations = IWL3945_STATION_COUNT; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 6d77039b4ed2..1a622aa5a160 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1999,7 +1999,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, static void iwl4965_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ab5b9d8d66be..17555c7c1d67 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -423,7 +423,7 @@ static int iwl5000_send_calib_cfg(struct iwl_priv *priv) static void iwl5000_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; int index; @@ -1143,7 +1143,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, static void iwl5000_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0878b34ee586..fc7a51144f0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -524,7 +524,7 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv, static void iwl_rx_reply_alive(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_alive_resp *palive; struct delayed_work *pwork; @@ -610,7 +610,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl4965_beacon_notif *beacon = (struct iwl4965_beacon_notif *)pkt->u.raw; u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); @@ -634,7 +634,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv, static void iwl_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; @@ -786,10 +786,10 @@ void iwl_rx_handle(struct iwl_priv *priv) rxq->queue[i] = NULL; - pci_unmap_single(priv->pci_dev, rxb->real_dma_addr, - priv->hw_params.rx_buf_size + 256, - PCI_DMA_FROMDEVICE); - pkt = (struct iwl_rx_packet *)rxb->skb->data; + pci_unmap_page(priv->pci_dev, rxb->page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + pkt = rxb_addr(rxb); trace_iwlwifi_dev_rx(priv, pkt, le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); @@ -825,10 +825,10 @@ void iwl_rx_handle(struct iwl_priv *priv) } if (reclaim) { - /* Invoke any callbacks, transfer the skb to caller, and - * fire off the (possibly) blocking iwl_send_cmd() + /* Invoke any callbacks, transfer the buffer to caller, + * and fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ - if (rxb && rxb->skb) + if (rxb && rxb->page) iwl_tx_cmd_complete(priv, rxb); else IWL_WARN(priv, "Claim null rxb?\n"); @@ -837,10 +837,10 @@ void iwl_rx_handle(struct iwl_priv *priv) /* For now we just don't re-use anything. We can tweak this * later to try and re-use notification packets and SKBs that * fail to Rx correctly */ - if (rxb->skb != NULL) { - priv->alloc_rxb_skb--; - dev_kfree_skb_any(rxb->skb); - rxb->skb = NULL; + if (rxb->page != NULL) { + priv->alloc_rxb_page--; + __free_pages(rxb->page, priv->hw_params.rx_page_order); + rxb->page = NULL; } spin_lock_irqsave(&rxq->lock, flags); @@ -907,6 +907,8 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) } #endif + spin_unlock_irqrestore(&priv->lock, flags); + /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not * atomic, make sure that inta covers all the interrupts that * we've discovered, even if FH interrupt came in just after @@ -928,8 +930,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) handled |= CSR_INT_BIT_HW_ERR; - spin_unlock_irqrestore(&priv->lock, flags); - return; } @@ -1056,7 +1056,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); } #endif - spin_unlock_irqrestore(&priv->lock, flags); } /* tasklet for iwlagn interrupt */ @@ -1086,6 +1085,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) inta, inta_mask); } #endif + + spin_unlock_irqrestore(&priv->lock, flags); + /* saved interrupt in inta variable now we can reset priv->inta */ priv->inta = 0; @@ -1101,8 +1103,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) handled |= CSR_INT_BIT_HW_ERR; - spin_unlock_irqrestore(&priv->lock, flags); - return; } @@ -1242,14 +1242,10 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) inta & ~priv->inta_mask); } - /* Re-enable all interrupts */ /* only Re-enable if diabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_enable_interrupts(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - } diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index cc4e9122709e..7d4f131708f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3544,6 +3544,16 @@ struct iwl_wimax_coex_cmd { *****************************************************************************/ struct iwl_rx_packet { + /* + * The first 4 bytes of the RX frame header contain both the RX frame + * size and some flags. + * Bit fields: + * 31: flag flush RB request + * 30: flag ignore TC (terminal counter) request + * 29: flag fast IRQ request + * 28-14: Reserved + * 13-00: RX frame size + */ __le32 len_n_flags; struct iwl_cmd_header hdr; union { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2ae168af0f2c..3e6ce5ce36aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1281,7 +1281,7 @@ static void iwl_set_rate(struct iwl_priv *priv) void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; struct iwl_csa_notification *csa = &(pkt->u.csa_notif); IWL_DEBUG_11H(priv, "CSA notif: channel %d, status %d\n", @@ -1492,10 +1492,9 @@ int iwl_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; if (priv->cfg->mod_params->amsdu_size_8K) - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; + priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K); else - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; - priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; + priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K); priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL; @@ -2176,7 +2175,7 @@ void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", sleep->pm_sleep_mode, sleep->pm_wakeup_src); @@ -2187,7 +2186,7 @@ EXPORT_SYMBOL(iwl_rx_pm_sleep_notif); 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; + struct iwl_rx_packet *pkt = rxb_addr(rxb); 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", len, @@ -2199,7 +2198,7 @@ EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); void iwl_rx_reply_error(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) " "seq 0x%04X ser 0x%08X\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index cec673badf0e..b877f8893fdf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -531,7 +531,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, void (*callback)(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb)); + struct iwl_rx_packet *pkt)); int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 451aa65b1a56..35d579455c3c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -146,12 +146,13 @@ extern void iwl5000_temperature(struct iwl_priv *priv); #define DEFAULT_LONG_RETRY_LIMIT 4U struct iwl_rx_mem_buffer { - dma_addr_t real_dma_addr; - dma_addr_t aligned_dma_addr; - struct sk_buff *skb; + dma_addr_t page_dma; + struct page *page; struct list_head list; }; +#define rxb_addr(r) page_address(r->page) + /* defined below */ struct iwl_device_cmd; @@ -167,7 +168,7 @@ struct iwl_cmd_meta { */ void (*callback)(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb); + struct iwl_rx_packet *pkt); /* The CMD_SIZE_HUGE flag bit indicates that the command * structure is stored at the end of the shared queue memory. */ @@ -366,6 +367,13 @@ enum { #define IWL_CMD_MAX_PAYLOAD 320 +/* + * IWL_LINK_HDR_MAX should include ieee80211_hdr, radiotap header, + * SNAP header and alignment. It should also be big enough for 802.11 + * control frames. + */ +#define IWL_LINK_HDR_MAX 64 + /** * struct iwl_device_cmd * @@ -390,10 +398,10 @@ struct iwl_device_cmd { struct iwl_host_cmd { const void *data; - struct sk_buff *reply_skb; + unsigned long reply_page; void (*callback)(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb); + struct iwl_rx_packet *pkt); u32 flags; u16 len; u8 id; @@ -650,7 +658,7 @@ struct iwl_sensitivity_ranges { * @valid_tx/rx_ant: usable antennas * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) * @max_rxq_log: Log-base-2 of max_rxq_size - * @rx_buf_size: Rx buffer size + * @rx_page_order: Rx buffer page order * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR * @max_stations: * @bcast_sta_id: @@ -673,9 +681,8 @@ struct iwl_hw_params { u8 valid_rx_ant; u16 max_rxq_size; u16 max_rxq_log; - u32 rx_buf_size; + u32 rx_page_order; u32 rx_wrt_ptr_reg; - u32 max_pkt_size; u8 max_stations; u8 bcast_sta_id; u8 ht40_channel; @@ -987,7 +994,7 @@ struct iwl_priv { int frames_count; enum ieee80211_band band; - int alloc_rxb_skb; + int alloc_rxb_page; void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 532c8d6cd8da..22a21a1c7f49 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -103,17 +103,8 @@ EXPORT_SYMBOL(get_cmd_string); static void iwl_generic_cmd_callback(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb) + struct iwl_rx_packet *pkt) { - struct iwl_rx_packet *pkt = NULL; - - if (!skb) { - IWL_ERR(priv, "Error: Response NULL in %s.\n", - get_cmd_string(cmd->hdr.cmd)); - return; - } - - pkt = (struct iwl_rx_packet *)skb->data; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); @@ -215,7 +206,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ret = -EIO; goto fail; } - if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) { + if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) { IWL_ERR(priv, "Error: Response NULL in '%s'\n", get_cmd_string(cmd->id)); ret = -EIO; @@ -237,9 +228,9 @@ cancel: ~CMD_WANT_SKB; } fail: - if (cmd->reply_skb) { - dev_kfree_skb_any(cmd->reply_skb); - cmd->reply_skb = NULL; + if (cmd->reply_page) { + free_pages(cmd->reply_page, priv->hw_params.rx_page_order); + cmd->reply_page = 0; } out: clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status); @@ -272,7 +263,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, void (*callback)(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb)) + struct iwl_rx_packet *pkt)) { struct iwl_host_cmd cmd = { .id = id, diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 7ad327ef9cb5..0a407f79de01 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -200,7 +200,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) list_del(element); /* Point to Rx buffer via next RBD in circular buffer */ - rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->aligned_dma_addr); + rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->page_dma); rxq->queue[rxq->write] = rxb; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->free_count--; @@ -239,7 +239,7 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl_rx_mem_buffer *rxb; - struct sk_buff *skb; + struct page *page; unsigned long flags; while (1) { @@ -252,29 +252,34 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) if (rxq->free_count > RX_LOW_WATERMARK) priority |= __GFP_NOWARN; - /* Alloc a new receive buffer */ - skb = alloc_skb(priv->hw_params.rx_buf_size + 256, - priority); - if (!skb) { + if (priv->hw_params.rx_page_order > 0) + priority |= __GFP_COMP; + + /* Alloc a new receive buffer */ + page = alloc_pages(priority, priv->hw_params.rx_page_order); + if (!page) { if (net_ratelimit()) - IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n"); + IWL_DEBUG_INFO(priv, "alloc_pages failed, " + "order: %d\n", + priv->hw_params.rx_page_order); + if ((rxq->free_count <= RX_LOW_WATERMARK) && net_ratelimit()) - IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n", + IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n", priority == GFP_ATOMIC ? "GFP_ATOMIC" : "GFP_KERNEL", rxq->free_count); /* We don't reschedule replenish work here -- we will * call the restock method and if it still needs * more buffers it will schedule replenish */ - break; + return; } spin_lock_irqsave(&rxq->lock, flags); if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); - dev_kfree_skb_any(skb); + __free_pages(page, priv->hw_params.rx_page_order); return; } element = rxq->rx_used.next; @@ -283,24 +288,21 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) spin_unlock_irqrestore(&rxq->lock, flags); - rxb->skb = skb; - /* Get physical address of RB/SKB */ - rxb->real_dma_addr = pci_map_single( - priv->pci_dev, - rxb->skb->data, - priv->hw_params.rx_buf_size + 256, - PCI_DMA_FROMDEVICE); + rxb->page = page; + /* Get physical address of the RB */ + rxb->page_dma = pci_map_page(priv->pci_dev, page, 0, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); /* dma address must be no more than 36 bits */ - BUG_ON(rxb->real_dma_addr & ~DMA_BIT_MASK(36)); + BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); /* and also 256 byte aligned! */ - rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256); - skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr); + BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); spin_lock_irqsave(&rxq->lock, flags); list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; - priv->alloc_rxb_skb++; + priv->alloc_rxb_page++; spin_unlock_irqrestore(&rxq->lock, flags); } @@ -336,12 +338,14 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { int i; for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].real_dma_addr, - priv->hw_params.rx_buf_size + 256, - PCI_DMA_FROMDEVICE); - dev_kfree_skb(rxq->pool[i].skb); + if (rxq->pool[i].page != NULL) { + pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + __free_pages(rxq->pool[i].page, + priv->hw_params.rx_page_order); + rxq->pool[i].page = NULL; + priv->alloc_rxb_page--; } } @@ -405,14 +409,14 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { /* In the reset function, these buffers may have been allocated * to an SKB, so we need to unmap and free potential storage */ - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].real_dma_addr, - priv->hw_params.rx_buf_size + 256, - PCI_DMA_FROMDEVICE); - priv->alloc_rxb_skb--; - dev_kfree_skb(rxq->pool[i].skb); - rxq->pool[i].skb = NULL; + if (rxq->pool[i].page != NULL) { + pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + priv->alloc_rxb_page--; + __free_pages(rxq->pool[i].page, + priv->hw_params.rx_page_order); + rxq->pool[i].page = NULL; } list_add_tail(&rxq->pool[i].list, &rxq->rx_used); } @@ -491,7 +495,7 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_missed_beacon_notif *missed_beacon; missed_beacon = &pkt->u.missed_beacon; @@ -592,7 +596,7 @@ void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { int change; - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(priv->statistics), @@ -919,6 +923,9 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) { + struct sk_buff *skb; + int ret = 0; + /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { IWL_DEBUG_DROP_LIMIT(priv, @@ -931,15 +938,38 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; - /* Resize SKB from mac header to end of packet */ - skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data); - skb_put(rxb->skb, len); + skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC); + if (!skb) { + IWL_ERR(priv, "alloc_skb failed\n"); + return; + } + + skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); + + /* mac80211 currently doesn't support paged SKB. Convert it to + * linear SKB for management frame and data frame requires + * software decryption or software defragementation. */ + if (ieee80211_is_mgmt(hdr->frame_control) || + ieee80211_has_protected(hdr->frame_control) || + ieee80211_has_morefrags(hdr->frame_control) || + le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) + ret = skb_linearize(skb); + else + ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ? + 0 : -ENOMEM; + + if (ret) { + kfree_skb(skb); + goto out; + } 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--; - rxb->skb = NULL; + memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); + + ieee80211_rx(priv->hw, skb); + out: + priv->alloc_rxb_page--; + rxb->page = NULL; } /* This is necessary only for a number of statistics, see the caller. */ @@ -967,7 +997,7 @@ 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; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_phy_res *phy_res; __le32 rx_pkt_status; struct iwl4965_rx_mpdu_res_start *amsdu; @@ -1128,7 +1158,7 @@ EXPORT_SYMBOL(iwl_rx_reply_rx); void iwl_rx_reply_rx_phy(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); priv->last_phy_res[0] = 1; memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), sizeof(struct iwl_rx_phy_res)); diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 41f9a0621250..4fca65a2fe9c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -111,7 +111,7 @@ EXPORT_SYMBOL(iwl_scan_cancel_timeout); static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret = 0; - struct iwl_rx_packet *res; + struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .flags = CMD_WANT_SKB, @@ -131,21 +131,21 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) return ret; } - res = (struct iwl_rx_packet *)cmd.reply_skb->data; - if (res->u.status != CAN_ABORT_STATUS) { + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be * due to simply not being in an active scan which * can occur if we send the scan abort before we * the microcode has notified us that a scan is * completed. */ - IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", res->u.status); + IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", pkt->u.status); clear_bit(STATUS_SCAN_ABORTING, &priv->status); clear_bit(STATUS_SCAN_HW, &priv->status); } - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.reply_skb); + priv->alloc_rxb_page--; + free_pages(cmd.reply_page, priv->hw_params.rx_page_order); return ret; } @@ -155,7 +155,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scanreq_notification *notif = (struct iwl_scanreq_notification *)pkt->u.raw; @@ -167,7 +167,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv, static void iwl_rx_scan_start_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scanstart_notification *notif = (struct iwl_scanstart_notification *)pkt->u.raw; priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); @@ -186,7 +186,7 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scanresults_notification *notif = (struct iwl_scanresults_notification *)pkt->u.raw; @@ -213,7 +213,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c index 022bcf115731..1ea5cd345fe8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.c +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c @@ -177,7 +177,7 @@ static int iwl_get_measurement(struct iwl_priv *priv, static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); if (!report->state) { diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index c6633fec8216..dc74c16d36a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -99,32 +99,25 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) static void iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb) + struct iwl_rx_packet *pkt) { - struct iwl_rx_packet *res = NULL; struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)cmd->cmd.payload; u8 sta_id = addsta->sta.sta_id; - if (!skb) { - IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n"); - return; - } - - res = (struct iwl_rx_packet *)skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", - res->hdr.flags); + pkt->hdr.flags); return; } - switch (res->u.add_sta.status) { + switch (pkt->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: iwl_sta_ucode_activate(priv, sta_id); /* fall through */ default: IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", - res->u.add_sta.status); + pkt->u.add_sta.status); break; } } @@ -132,7 +125,7 @@ static void iwl_add_sta_callback(struct iwl_priv *priv, int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags) { - struct iwl_rx_packet *res = NULL; + struct iwl_rx_packet *pkt = NULL; int ret = 0; u8 data[sizeof(*sta)]; struct iwl_host_cmd cmd = { @@ -152,15 +145,15 @@ int iwl_send_add_sta(struct iwl_priv *priv, if (ret || (flags & CMD_ASYNC)) return ret; - res = (struct iwl_rx_packet *)cmd.reply_skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", - res->hdr.flags); + pkt->hdr.flags); ret = -EIO; } if (ret == 0) { - switch (res->u.add_sta.status) { + switch (pkt->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: iwl_sta_ucode_activate(priv, sta->sta.sta_id); IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); @@ -172,8 +165,8 @@ int iwl_send_add_sta(struct iwl_priv *priv, } } - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.reply_skb); + priv->alloc_rxb_page--; + free_pages(cmd.reply_page, priv->hw_params.rx_page_order); return ret; } @@ -324,26 +317,19 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) static void iwl_remove_sta_callback(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb) + struct iwl_rx_packet *pkt) { - struct iwl_rx_packet *res = NULL; struct iwl_rem_sta_cmd *rm_sta = - (struct iwl_rem_sta_cmd *)cmd->cmd.payload; + (struct iwl_rem_sta_cmd *)cmd->cmd.payload; const char *addr = rm_sta->addr; - if (!skb) { - IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n"); - return; - } - - res = (struct iwl_rx_packet *)skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", - res->hdr.flags); + pkt->hdr.flags); return; } - switch (res->u.rem_sta.status) { + switch (pkt->u.rem_sta.status) { case REM_STA_SUCCESS_MSK: iwl_sta_ucode_deactivate(priv, addr); break; @@ -356,7 +342,7 @@ static void iwl_remove_sta_callback(struct iwl_priv *priv, static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, u8 flags) { - struct iwl_rx_packet *res = NULL; + struct iwl_rx_packet *pkt; int ret; struct iwl_rem_sta_cmd rm_sta_cmd; @@ -381,15 +367,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, if (ret || (flags & CMD_ASYNC)) return ret; - res = (struct iwl_rx_packet *)cmd.reply_skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", - res->hdr.flags); + pkt->hdr.flags); ret = -EIO; } if (!ret) { - switch (res->u.rem_sta.status) { + switch (pkt->u.rem_sta.status) { case REM_STA_SUCCESS_MSK: iwl_sta_ucode_deactivate(priv, addr); IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); @@ -401,8 +387,8 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, } } - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.reply_skb); + priv->alloc_rxb_page--; + free_pages(cmd.reply_page, priv->hw_params.rx_page_order); return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index d0bd7cd024ad..5c43d7c43b30 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1153,7 +1153,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, */ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); @@ -1180,10 +1180,10 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { - meta->source->reply_skb = rxb->skb; - rxb->skb = NULL; + meta->source->reply_page = (unsigned long)rxb_addr(rxb); + rxb->page = NULL; } else if (meta->callback) - meta->callback(priv, cmd, rxb->skb); + meta->callback(priv, cmd, pkt); iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); @@ -1442,7 +1442,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; struct iwl_tx_queue *txq = NULL; struct iwl_ht_agg *agg; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 515f29b8a7a7..5977a57a234c 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -745,7 +745,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, u8 type) { struct iwl_spectrum_cmd spectrum; - struct iwl_rx_packet *res; + struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = REPLY_SPECTRUM_MEASUREMENT_CMD, .data = (void *)&spectrum, @@ -790,18 +790,18 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.reply_skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n"); rc = -EIO; } - spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); + spectrum_resp_status = le16_to_cpu(pkt->u.spectrum.status); switch (spectrum_resp_status) { case 0: /* Command will be handled */ - if (res->u.spectrum.id != 0xff) { + if (pkt->u.spectrum.id != 0xff) { IWL_DEBUG_INFO(priv, "Replaced existing measurement: %d\n", - res->u.spectrum.id); + pkt->u.spectrum.id); priv->measurement_status &= ~MEASUREMENT_READY; } priv->measurement_status |= MEASUREMENT_ACTIVE; @@ -813,7 +813,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, break; } - dev_kfree_skb_any(cmd.reply_skb); + free_pages(cmd.reply_page, priv->hw_params.rx_page_order); return rc; } @@ -822,7 +822,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, static void iwl3945_rx_reply_alive(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_alive_resp *palive; struct delayed_work *pwork; @@ -859,7 +859,7 @@ static void iwl3945_rx_reply_add_sta(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); #endif IWL_DEBUG_RX(priv, "Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); @@ -895,7 +895,7 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status); u8 rate = beacon->beacon_notify_hdr.rate; @@ -918,7 +918,7 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv, static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; @@ -1082,7 +1082,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) list_del(element); /* Point to Rx buffer via next RBD in circular buffer */ - rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->real_dma_addr); + rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->page_dma); rxq->queue[rxq->write] = rxb; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->free_count--; @@ -1122,7 +1122,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl_rx_mem_buffer *rxb; - struct sk_buff *skb; + struct page *page; unsigned long flags; while (1) { @@ -1136,9 +1136,13 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) if (rxq->free_count > RX_LOW_WATERMARK) priority |= __GFP_NOWARN; + + if (priv->hw_params.rx_page_order > 0) + priority |= __GFP_COMP; + /* Alloc a new receive buffer */ - skb = alloc_skb(priv->hw_params.rx_buf_size, priority); - if (!skb) { + page = alloc_pages(priority, priv->hw_params.rx_page_order); + if (!page) { if (net_ratelimit()) IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n"); if ((rxq->free_count <= RX_LOW_WATERMARK) && @@ -1155,7 +1159,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) spin_lock_irqsave(&rxq->lock, flags); if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); - dev_kfree_skb_any(skb); + __free_pages(page, priv->hw_params.rx_page_order); return; } element = rxq->rx_used.next; @@ -1163,26 +1167,18 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) list_del(element); spin_unlock_irqrestore(&rxq->lock, flags); - rxb->skb = skb; - - /* If radiotap head is required, reserve some headroom here. - * The physical head count is a variable rx_stats->phy_count. - * We reserve 4 bytes here. Plus these extra bytes, the - * headroom of the physical head should be enough for the - * radiotap head that iwl3945 supported. See iwl3945_rt. - */ - skb_reserve(rxb->skb, 4); - + rxb->page = page; /* Get physical address of RB/SKB */ - rxb->real_dma_addr = pci_map_single(priv->pci_dev, - rxb->skb->data, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); + rxb->page_dma = pci_map_page(priv->pci_dev, page, 0, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &rxq->rx_free); - priv->alloc_rxb_skb++; rxq->free_count++; + priv->alloc_rxb_page++; + spin_unlock_irqrestore(&rxq->lock, flags); } } @@ -1198,14 +1194,14 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { /* In the reset function, these buffers may have been allocated * to an SKB, so we need to unmap and free potential storage */ - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].real_dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - priv->alloc_rxb_skb--; - dev_kfree_skb(rxq->pool[i].skb); - rxq->pool[i].skb = NULL; + if (rxq->pool[i].page != NULL) { + pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + priv->alloc_rxb_page--; + __free_pages(rxq->pool[i].page, + priv->hw_params.rx_page_order); + rxq->pool[i].page = NULL; } list_add_tail(&rxq->pool[i].list, &rxq->rx_used); } @@ -1213,8 +1209,8 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* Set us so that we have processed and used all buffers, but have * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; - rxq->free_count = 0; rxq->write_actual = 0; + rxq->free_count = 0; spin_unlock_irqrestore(&rxq->lock, flags); } @@ -1247,12 +1243,14 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx { int i; for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].real_dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - dev_kfree_skb(rxq->pool[i].skb); + if (rxq->pool[i].page != NULL) { + pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + __free_pages(rxq->pool[i].page, + priv->hw_params.rx_page_order); + rxq->pool[i].page = NULL; + priv->alloc_rxb_page--; } } @@ -1388,10 +1386,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) rxq->queue[i] = NULL; - pci_unmap_single(priv->pci_dev, rxb->real_dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - pkt = (struct iwl_rx_packet *)rxb->skb->data; + pci_unmap_page(priv->pci_dev, rxb->page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + pkt = rxb_addr(rxb); trace_iwlwifi_dev_rx(priv, pkt, le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); @@ -1416,16 +1414,17 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; } else { /* No handling needed */ - IWL_DEBUG_RX(priv, "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); } if (reclaim) { - /* Invoke any callbacks, transfer the skb to caller, and - * fire off the (possibly) blocking iwl_send_cmd() + /* Invoke any callbacks, transfer the buffer to caller, + * and fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ - if (rxb && rxb->skb) + if (rxb && rxb->page) iwl_tx_cmd_complete(priv, rxb); else IWL_WARN(priv, "Claim null rxb?\n"); @@ -1434,10 +1433,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) /* For now we just don't re-use anything. We can tweak this * later to try and re-use notification packets and SKBs that * fail to Rx correctly */ - if (rxb->skb != NULL) { - priv->alloc_rxb_skb--; - dev_kfree_skb_any(rxb->skb); - rxb->skb = NULL; + if (rxb->page != NULL) { + priv->alloc_rxb_page--; + __free_pages(rxb->page, priv->hw_params.rx_page_order); + rxb->page = NULL; } spin_lock_irqsave(&rxq->lock, flags); @@ -1678,6 +1677,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) } #endif + spin_unlock_irqrestore(&priv->lock, flags); + /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not * atomic, make sure that inta covers all the interrupts that * we've discovered, even if FH interrupt came in just after @@ -1699,8 +1700,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) handled |= CSR_INT_BIT_HW_ERR; - spin_unlock_irqrestore(&priv->lock, flags); - return; } @@ -1792,7 +1791,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); } #endif - spin_unlock_irqrestore(&priv->lock, flags); } static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, -- cgit v1.2.3 From 1f80989e8b7f79d8e916b14600488489bdd5569f Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 16 Oct 2009 14:25:49 -0700 Subject: iwl3945: disable all tx fifos Disable the all the tx fifos while stopping the tx queues. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index b188a026637a..9f18b4cba952 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1219,6 +1219,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) /* stop SCD */ iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); + iwl_write_prph(priv, ALM_SCD_TXFACT_REG, 0); /* reset TFD queues */ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { -- cgit v1.2.3 From c09430abed4159e5c56aaea257d040f7452daba6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:50 -0700 Subject: iwlwifi: show current power save status reported by uCode Power save request is sent from driver to uCode, but there is no indication from uCode about the current device power save state. Reading GP_CNTRL register bit 25:24 to show the current power save status 00: no power save 01: MAC power down 10: PHY power down 11: Error The uCode could switch in and out of power save mode in the order of once per 100-300 ms in many cases. The reading here should just be used for reference on the current uCode power save status. Do not confuse this reading with the PowerSave set by driver and mac80211. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-csr.h | 5 +++++ drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 26 ++++++++++++++++++++++++++ 3 files changed, 32 insertions(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 8f183e0fa512..401e1e01be67 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -235,6 +235,11 @@ #define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ #define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ #define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ +#define CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */ +#define CSR_GP_REG_NO_POWER_SAVE (0x00000000) +#define CSR_GP_REG_MAC_POWER_SAVE (0x01000000) +#define CSR_GP_REG_PHY_POWER_SAVE (0x02000000) +#define CSR_GP_REG_POWER_SAVE_ERROR (0x03000000) /* EEPROM signature */ #define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000) diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index b9ca475cc61c..96c92eab692a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -106,6 +106,7 @@ struct iwl_debugfs { struct dentry *file_sensitivity; struct dentry *file_chain_noise; struct dentry *file_tx_power; + struct dentry *file_power_save_status; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 2cd11ba96370..e78cd26b809f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1802,6 +1802,29 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t iwl_dbgfs_power_save_status_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[60]; + int pos = 0; + const size_t bufsz = sizeof(buf); + u32 pwrsave_status; + + pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_REG_POWER_SAVE_STATUS_MSK; + + pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: "); + pos += scnprintf(buf + pos, bufsz - pos, "%s\n", + (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" : + (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" : + (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" : + "error"); + + 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); @@ -1813,6 +1836,7 @@ DEBUGFS_READ_FILE_OPS(ucode_general_stats); DEBUGFS_READ_FILE_OPS(sensitivity); DEBUGFS_READ_FILE_OPS(chain_noise); DEBUGFS_READ_FILE_OPS(tx_power); +DEBUGFS_READ_FILE_OPS(power_save_status); /* * Create the debugfs files and directories @@ -1860,6 +1884,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(rx_queue, debug); DEBUGFS_ADD_FILE(tx_queue, debug); DEBUGFS_ADD_FILE(tx_power, debug); + DEBUGFS_ADD_FILE(power_save_status, 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); @@ -1912,6 +1937,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) 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); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status); 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); -- cgit v1.2.3 From 32b7e244f2b1082ac0a1cda1b088574f2d590496 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:51 -0700 Subject: iwlwifi: identify eeprom version for 6x50 series NIC Adding support for 6x50 series EEPROM version check, 6x50 is wifi/wimax combo device which has different EEPROM map Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index bdc1c74b6820..e74dad3280cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -399,7 +399,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .num_of_queues = IWL50_NUM_QUEUES, .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, @@ -425,7 +425,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .sku = IWL_SKU_A|IWL_SKU_G, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .num_of_queues = IWL50_NUM_QUEUES, .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, @@ -476,7 +476,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .num_of_queues = IWL50_NUM_QUEUES, .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index b363c96fd6c6..5ba5a4e9e49a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -261,9 +261,12 @@ struct iwl_eeprom_enhanced_txpwr { /* 1000 Specific */ #define EEPROM_1000_EEPROM_VERSION (0x15C) -/* 60x0 Specific */ +/* 6x00 Specific */ #define EEPROM_6000_EEPROM_VERSION (0x434) +/* 6x50 Specific */ +#define EEPROM_6050_EEPROM_VERSION (0x532) + /* OTP */ /* lower blocks contain EEPROM image and calibration data */ #define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ -- cgit v1.2.3 From 3ab312a893bbfc0fad7b1b644b3d477905773b1a Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:52 -0700 Subject: iwlwifi: fix incorrect otp blocks number for 6x50 series For 6x50 series, number of OTP blocks is different from 6x00 series Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index e74dad3280cc..887e4e3674cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -408,7 +408,7 @@ 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, + .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, @@ -434,7 +434,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, @@ -485,7 +485,7 @@ 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, + .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, -- cgit v1.2.3 From f0b6e2e8cbc6026d3d6d3087032f5eceafaee0b8 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 16 Oct 2009 14:25:53 -0700 Subject: iwlwifi: move iwl_setup_mac to iwlagn This function is only used in iwlagn so there is no need to have it in iwlcore. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 62 +++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 58 ------------------------------ drivers/net/wireless/iwlwifi/iwl-core.h | 1 - 3 files changed, 62 insertions(+), 59 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index fc7a51144f0c..6c4fa011a924 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2284,6 +2284,68 @@ void iwl_post_associate(struct iwl_priv *priv) #define UCODE_READY_TIMEOUT (4 * HZ) +/* + * Not a mac80211 entry point function, but it fits in with all the + * other mac80211 functions grouped here. + */ +static int iwl_setup_mac(struct iwl_priv *priv) +{ + int ret; + struct ieee80211_hw *hw = priv->hw; + hw->rate_control_algorithm = "iwl-agn-rs"; + + /* Tell mac80211 our characteristics */ + hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_SPECTRUM_MGMT; + + if (!priv->cfg->broken_powersave) + hw->flags |= 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; + + /* Default value; 4 EDCA QOS priorities */ + hw->queues = 4; + + hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; + + if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &priv->bands[IEEE80211_BAND_2GHZ]; + if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &priv->bands[IEEE80211_BAND_5GHZ]; + + ret = ieee80211_register_hw(priv->hw); + if (ret) { + IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); + return ret; + } + priv->mac80211_registered = 1; + + return 0; +} + + static int iwl_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 3e6ce5ce36aa..7ce8663fdb7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1429,64 +1429,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw, } EXPORT_SYMBOL(iwl_configure_filter); -int iwl_setup_mac(struct iwl_priv *priv) -{ - int ret; - struct ieee80211_hw *hw = priv->hw; - hw->rate_control_algorithm = "iwl-agn-rs"; - - /* Tell mac80211 our characteristics */ - hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM | - IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_SPECTRUM_MGMT; - - if (!priv->cfg->broken_powersave) - hw->flags |= 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; - - /* Default value; 4 EDCA QOS priorities */ - hw->queues = 4; - - hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; - - if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->bands[IEEE80211_BAND_2GHZ]; - if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->bands[IEEE80211_BAND_5GHZ]; - - ret = ieee80211_register_hw(priv->hw); - if (ret) { - IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); - return ret; - } - priv->mac80211_registered = 1; - - return 0; -} -EXPORT_SYMBOL(iwl_setup_mac); - int iwl_set_hw_params(struct iwl_priv *priv) { priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b877f8893fdf..a2a580df3d99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -305,7 +305,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, 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); int iwl_init_drv(struct iwl_priv *priv); void iwl_uninit_drv(struct iwl_priv *priv); -- cgit v1.2.3 From cc1282f63b53d0967bd96ed56aa3d2463dc4b4b6 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 16 Oct 2009 14:25:54 -0700 Subject: iwlwifi: move rate scaling structures to header file Move to header file so they can be included and used in other parts of the driver. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 100 ----------------------------- drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 101 ++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 100 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index a07be29cc5e5..2d4ec1a65957 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -75,106 +75,6 @@ static const u8 ant_toggle_lookup[] = { /*ANT_ABC -> */ ANT_ABC, }; -/** - * struct iwl_rate_scale_data -- tx success history for one rate - */ -struct iwl_rate_scale_data { - u64 data; /* bitmap of successful frames */ - s32 success_counter; /* number of frames successful */ - s32 success_ratio; /* per-cent * 128 */ - s32 counter; /* number of frames attempted */ - s32 average_tpt; /* success ratio * expected throughput */ - unsigned long stamp; -}; - -/** - * struct iwl_scale_tbl_info -- tx params and success history for all rates - * - * There are two of these in struct iwl_lq_sta, - * one for "active", and one for "search". - */ -struct iwl_scale_tbl_info { - enum iwl_table_type lq_type; - u8 ant_type; - u8 is_SGI; /* 1 = short guard interval */ - 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 */ - s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ - u32 current_rate; /* rate_n_flags, uCode API format */ - struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ -}; - -struct iwl_traffic_load { - unsigned long time_stamp; /* age of the oldest statistics */ - u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time - * slice */ - u32 total; /* total num of packets during the - * last TID_MAX_TIME_DIFF */ - u8 queue_count; /* number of queues that has - * been used since the last cleanup */ - u8 head; /* start of the circular buffer */ -}; - -/** - * struct iwl_lq_sta -- driver's rate scaling private structure - * - * Pointer to this gets passed back and forth between driver and mac80211. - */ -struct iwl_lq_sta { - u8 active_tbl; /* index of active table, range 0-1 */ - u8 enable_counter; /* indicates HT mode */ - u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */ - u8 search_better_tbl; /* 1: currently trying alternate mode */ - s32 last_tpt; - - /* The following determine when to search for a new mode */ - u32 table_count_limit; - u32 max_failure_limit; /* # failed frames before new search */ - u32 max_success_limit; /* # successful frames before new search */ - u32 table_count; - u32 total_failed; /* total failed frames, any/all rates */ - u32 total_success; /* total successful frames, any/all rates */ - u64 flush_timer; /* time staying in mode before new search */ - - u8 action_counter; /* # mode-switch actions tried */ - u8 is_green; - u8 is_dup; - enum ieee80211_band band; - u8 ibss_sta_added; - - /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ - u32 supp_rates; - u16 active_legacy_rate; - u16 active_siso_rate; - u16 active_mimo2_rate; - u16 active_mimo3_rate; - u16 active_rate_basic; - s8 max_rate_idx; /* Max rate set by user */ - u8 missed_rate_counter; - - struct iwl_link_quality_cmd lq; - struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ - struct iwl_traffic_load load[TID_MAX_LOAD_COUNT]; - u8 tx_agg_tid_en; -#ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *rs_sta_dbgfs_scale_table_file; - struct dentry *rs_sta_dbgfs_stats_table_file; - struct dentry *rs_sta_dbgfs_rate_scale_data_file; - struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; - u32 dbg_fixed_rate; -#endif - struct iwl_priv *drv; - - /* used to be in sta_info */ - int last_txrate_idx; - /* last tx rate_n_flags */ - u32 last_rate_n_flags; - /* packets destined for this STA are aggregated */ - u8 is_agg; -}; - static void rs_rate_scale_perform(struct iwl_priv *priv, struct sk_buff *skb, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 9fac530cfb7e..affc0c5a2f2c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -54,6 +54,7 @@ struct iwl3945_rate_info { u8 prev_table_rs; /* prev in rate table cmd */ }; + /* * These serve as indexes into * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; @@ -335,6 +336,106 @@ struct iwl_rate_mcs_info { char mcs[IWL_MAX_MCS_DISPLAY_SIZE]; }; +/** + * struct iwl_rate_scale_data -- tx success history for one rate + */ +struct iwl_rate_scale_data { + u64 data; /* bitmap of successful frames */ + s32 success_counter; /* number of frames successful */ + s32 success_ratio; /* per-cent * 128 */ + s32 counter; /* number of frames attempted */ + s32 average_tpt; /* success ratio * expected throughput */ + unsigned long stamp; +}; + +/** + * struct iwl_scale_tbl_info -- tx params and success history for all rates + * + * There are two of these in struct iwl_lq_sta, + * one for "active", and one for "search". + */ +struct iwl_scale_tbl_info { + enum iwl_table_type lq_type; + u8 ant_type; + u8 is_SGI; /* 1 = short guard interval */ + 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 */ + s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ + u32 current_rate; /* rate_n_flags, uCode API format */ + struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ +}; + +struct iwl_traffic_load { + unsigned long time_stamp; /* age of the oldest statistics */ + u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time + * slice */ + u32 total; /* total num of packets during the + * last TID_MAX_TIME_DIFF */ + u8 queue_count; /* number of queues that has + * been used since the last cleanup */ + u8 head; /* start of the circular buffer */ +}; + +/** + * struct iwl_lq_sta -- driver's rate scaling private structure + * + * Pointer to this gets passed back and forth between driver and mac80211. + */ +struct iwl_lq_sta { + u8 active_tbl; /* index of active table, range 0-1 */ + u8 enable_counter; /* indicates HT mode */ + u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */ + u8 search_better_tbl; /* 1: currently trying alternate mode */ + s32 last_tpt; + + /* The following determine when to search for a new mode */ + u32 table_count_limit; + u32 max_failure_limit; /* # failed frames before new search */ + u32 max_success_limit; /* # successful frames before new search */ + u32 table_count; + u32 total_failed; /* total failed frames, any/all rates */ + u32 total_success; /* total successful frames, any/all rates */ + u64 flush_timer; /* time staying in mode before new search */ + + u8 action_counter; /* # mode-switch actions tried */ + u8 is_green; + u8 is_dup; + enum ieee80211_band band; + u8 ibss_sta_added; + + /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ + u32 supp_rates; + u16 active_legacy_rate; + u16 active_siso_rate; + u16 active_mimo2_rate; + u16 active_mimo3_rate; + u16 active_rate_basic; + s8 max_rate_idx; /* Max rate set by user */ + u8 missed_rate_counter; + + struct iwl_link_quality_cmd lq; + struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ + struct iwl_traffic_load load[TID_MAX_LOAD_COUNT]; + u8 tx_agg_tid_en; +#ifdef CONFIG_MAC80211_DEBUGFS + struct dentry *rs_sta_dbgfs_scale_table_file; + struct dentry *rs_sta_dbgfs_stats_table_file; + struct dentry *rs_sta_dbgfs_rate_scale_data_file; + struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; + u32 dbg_fixed_rate; +#endif + struct iwl_priv *drv; + + /* used to be in sta_info */ + int last_txrate_idx; + /* last tx rate_n_flags */ + u32 last_rate_n_flags; + /* packets destined for this STA are aggregated */ + u8 is_agg; +}; + static inline u8 num_of_ant(u8 mask) { return !!((mask) & ANT_A) + -- cgit v1.2.3 From 8d9698b3e6ce3c50f9ec5a0aaea4da82d5af7779 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 16 Oct 2009 14:25:55 -0700 Subject: iwlagn: store station rate scale information in mac80211 station structure Currently mac80211 initializes the rate scaling before notifying the driver of the station's existence. The driver dealt with this by not relying on mac80211's station notifications and instead mixing this functionality with the rate scaling code and other places. To clean this up the driver needs to do rate scaling initialization after being notified of the station, this can be done if the rate scaling information forms part of the station information passed from mac80211 to driver. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 8 ++------ drivers/net/wireless/iwlwifi/iwl-agn.c | 1 + drivers/net/wireless/iwlwifi/iwl-dev.h | 13 +++++++++++++ 3 files changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 2d4ec1a65957..27d4ece4d467 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2475,19 +2475,17 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl_lq_sta *lq_sta; + struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; struct iwl_priv *priv; int i, j; priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE(priv, "create station rate scale window\n"); - lq_sta = kzalloc(sizeof(struct iwl_lq_sta), gfp); + lq_sta = &sta_priv->lq_sta; - if (lq_sta == NULL) - return NULL; lq_sta->lq.sta_id = 0xff; - for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); @@ -2719,11 +2717,9 @@ static void rs_free(void *priv_rate) static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, void *priv_sta) { - struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_priv *priv __maybe_unused = priv_r; IWL_DEBUG_RATE(priv, "enter\n"); - kfree(lq_sta); IWL_DEBUG_RATE(priv, "leave\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6c4fa011a924..64d918787e88 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2304,6 +2304,7 @@ static int iwl_setup_mac(struct iwl_priv *priv) hw->flags |= IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + hw->sta_data_size = sizeof(struct iwl_station_priv); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 35d579455c3c..6ba082d6ab16 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -576,6 +576,19 @@ struct iwl_station_entry { struct iwl_hw_key keyinfo; }; +/* + * iwl_station_priv: Driver's private station information + * + * When mac80211 creates a station it reserves some space (hw->sta_data_size) + * in the structure for use by driver. This structure is places in that + * space. + * + * At the moment use it for the station's rate scaling information. + */ +struct iwl_station_priv { + struct iwl_lq_sta lq_sta; +}; + /* one for each uCode image (inst/data, boot/init/runtime) */ struct fw_desc { void *v_addr; /* access by driver */ -- cgit v1.2.3 From 32004ee42fced8b2372dd2f93e65cc9d71e8c4bf Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:56 -0700 Subject: iwlwifi: set auto clock gate disable bit for 6x00/6x50 series For 6x00 and 6x50 series NIC with OTP shadow RAM, set auto clock gate disable bit when initializing OTP access. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-csr.h | 6 ++++-- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 401e1e01be67..b6ed5a3147a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -109,8 +109,9 @@ * Bit fields: * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step */ -#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) -#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240) +#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) +#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240) +#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250) /* Bits for CSR_HW_IF_CONFIG_REG */ #define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) @@ -195,6 +196,7 @@ #define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) #define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) #define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) +#define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000) /* GP (general purpose) CONTROL */ #define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 2e8c40576d22..9429cb1c69bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -358,6 +358,14 @@ static int iwl_init_otp_access(struct iwl_priv *priv) udelay(5); iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); + + /* + * CSR auto clock gate disable bit - + * this is only applicable for HW with OTP shadow RAM + */ + if (priv->cfg->shadow_ram_support) + iwl_set_bit(priv, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); } return ret; } -- cgit v1.2.3 From 9444b188022418c624ce32584c3b9544b500d15e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:57 -0700 Subject: iwlwifi: no chain noise support for 6x50 series For initial bring up of 6x50 series NICs, no chain noise support in uCode, this feature will be added in the later stage of development. Two chain noise related functions are removed from 6x50 series: 1. gain computation 2. chain noise reset Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 887e4e3674cf..b53181324487 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -232,6 +232,21 @@ static struct iwl_ops iwl6000_ops = { .led = &iwlagn_led_ops, }; +static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = { + .get_hcmd_size = iwl5000_get_hcmd_size, + .build_addsta_hcmd = iwl5000_build_addsta_hcmd, + .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag, + .calc_rssi = iwl5000_calc_rssi, +}; + +static struct iwl_ops iwl6050_ops = { + .ucode = &iwl5000_ucode, + .lib = &iwl6000_lib, + .hcmd = &iwl5000_hcmd, + .utils = &iwl6050_hcmd_utils, + .led = &iwlagn_led_ops, +}; + /* * "h": Hybrid configuration, use both internal and external Power Amplifier @@ -397,7 +412,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000_ops, + .ops = &iwl6050_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, @@ -423,7 +438,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl6000_ops, + .ops = &iwl6050_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, @@ -474,7 +489,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000_ops, + .ops = &iwl6050_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, -- cgit v1.2.3 From 4ad177b5c860dc0b1083eccc55957daf4a116b90 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:58 -0700 Subject: iwlwifi: rework for static power save For static power save, the actual intervals are calculated by driver based on the default table and DTIM flag, then sent to uCode when the scheme is changed. Three tables are defined based on DTIM period. 1. DTIM 0 - 2 2. DTIM 3 - 10 3. DTIM > 11 The actual number of DTIM a station may miss may not exceed the following: . Only 1 DTIM may be skipped at PI=4 when allowed . Only 2 DTIMs may be skipped at PI=5 when allowed . DTIM may be skipped only 5 sec after last activity . DTIM may be skipped only 30 sec after connection establishment Only allow user to override the power_level when rf is ready to make sure power level gets changed upon request. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 5 +- drivers/net/wireless/iwlwifi/iwl-power.c | 75 +++++++++++++++++++++--------- drivers/net/wireless/iwlwifi/iwl-power.h | 2 + 3 files changed, 59 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index e78cd26b809f..8784911fd56e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -809,9 +809,12 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, if (value != -1 && (value < 0 || value >= IWL_POWER_NUM)) return -EINVAL; + if (!iwl_is_ready_rf(priv)) + return -EAGAIN; + priv->power_data.debug_sleep_level_override = value; - iwl_power_update_mode(priv, false); + iwl_power_update_mode(priv, true); return count; } diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 9c6b14952061..150ff87af33b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(no_sleep_autoadjust, struct iwl_power_vec_entry { struct iwl_powertable_cmd cmd; - u8 no_dtim; + u8 no_dtim; /* number of skip dtim */ }; #define IWL_DTIM_RANGE_0_MAX 2 @@ -83,8 +83,9 @@ struct iwl_power_vec_entry { cpu_to_le32(X4)} /* default power management (not Tx power) table values */ /* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */ +/* DTIM 0 - 2 */ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { - {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, + {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 1, 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}, {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1}, @@ -93,15 +94,17 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { /* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */ +/* DTIM 3 - 10 */ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { {{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}, {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1}, - {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} + {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 6, 10, 10)}, 2} }; /* for DTIM period > IWL_DTIM_RANGE_1_MAX */ +/* DTIM 11 - */ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { {{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}, @@ -115,13 +118,15 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, enum iwl_power_level lvl, int period) { const struct iwl_power_vec_entry *table; - int max_sleep, i; - bool skip; + int max_sleep[IWL_POWER_VEC_SIZE] = { 0 }; + int i; + u8 skip; + u32 slp_itrvl; table = range_2; - if (period < IWL_DTIM_RANGE_1_MAX) + if (period <= IWL_DTIM_RANGE_1_MAX) table = range_1; - if (period < IWL_DTIM_RANGE_0_MAX) + if (period <= IWL_DTIM_RANGE_0_MAX) table = range_0; BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); @@ -129,34 +134,60 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, *cmd = table[lvl].cmd; if (period == 0) { - skip = false; + skip = 0; period = 1; + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) + max_sleep[i] = 1; + } else { - skip = !!table[lvl].no_dtim; + skip = table[lvl].no_dtim; + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) + max_sleep[i] = le32_to_cpu(cmd->sleep_interval[i]); + max_sleep[IWL_POWER_VEC_SIZE - 1] = skip + 1; } - 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; + slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); + /* figure out the listen interval based on dtim period and skip */ + if (slp_itrvl == 0xFF) + cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = + cpu_to_le32(period * (skip + 1)); + + slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); + if (slp_itrvl > period) + cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = + cpu_to_le32((slp_itrvl / period) * period); + + if (skip) cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; - } else { - max_sleep = period; + else 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); + slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); + if (slp_itrvl > IWL_CONN_LISTEN_INTERVAL) + cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = + cpu_to_le32(IWL_CONN_LISTEN_INTERVAL); + + /* enforce max sleep interval */ + for (i = IWL_POWER_VEC_SIZE - 1; i >= 0 ; i--) { + if (le32_to_cpu(cmd->sleep_interval[i]) > + (max_sleep[i] * period)) + cmd->sleep_interval[i] = + cpu_to_le32(max_sleep[i] * period); + if (i != (IWL_POWER_VEC_SIZE - 1)) { + if (le32_to_cpu(cmd->sleep_interval[i]) > + le32_to_cpu(cmd->sleep_interval[i+1])) + cmd->sleep_interval[i] = + cmd->sleep_interval[i+1]; + } + } 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, "numSkipDtim = %u, dtimPeriod = %d\n", + skip, period); IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1); } diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 310c32e8f698..0755518f86e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -30,6 +30,8 @@ #include "iwl-commands.h" +#define IWL_CONN_LISTEN_INTERVAL 10 + #define IWL_ABSOLUTE_ZERO 0 #define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 -- cgit v1.2.3 From 1a5c3d61993f56daf15c35bea8d3943f4e835638 Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Fri, 23 Oct 2009 13:42:19 -0700 Subject: iwlwifi: add missing commands to syslog messages Two commands missing from list of commands such that when debug is enabled, these commands are shown as UNKNOWN. Missing commands are TX_ANT_CONFIGURATION_CMD and TEMPERATURE_NOTIFICATION. Signed-off-by: Jay Sternberg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 1 + drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 7d4f131708f3..1a7c0d02c19c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -114,6 +114,7 @@ enum { COEX_EVENT_CMD = 0x5c, /* Calibration */ + TEMPERATURE_NOTIFICATION = 0x62, CALIBRATION_CFG_CMD = 0x65, CALIBRATION_RES_NOTIFICATION = 0x66, CALIBRATION_COMPLETE_NOTIFICATION = 0x67, diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 22a21a1c7f49..f2a60dc4109f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -92,6 +92,8 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(CALIBRATION_RES_NOTIFICATION); IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); IWL_CMD(REPLY_TX_POWER_DBM_CMD); + IWL_CMD(TEMPERATURE_NOTIFICATION); + IWL_CMD(TX_ANT_CONFIGURATION_CMD); default: return "UNKNOWN"; -- cgit v1.2.3 From 065e63b00cf13919010bbeff48f7a120033be448 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:20 -0700 Subject: iwlwifi: fix gain computation for 5000 series and up In Rx gain balancing (chain noise) computation for 5000 series and up, the delta gain calculation should use the average noise of default chain, not "chain 0" which do not exist for all the devices. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 17555c7c1d67..afa88a304158 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -236,7 +236,7 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, data->delta_gain_code[i] = 0; continue; } - delta_g = (1000 * ((s32)average_noise[0] - + delta_g = (1000 * ((s32)average_noise[default_chain] - (s32)average_noise[i])) / 1500; /* bound gain by 2 bits value max, 3rd bit is sign */ data->delta_gain_code[i] = -- cgit v1.2.3 From fadb3582a38c33d0f7c58ab7905d4dbc67f4c4d9 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 23 Oct 2009 13:42:21 -0700 Subject: iwlwifi: consolidate apm_init() functions Consolidate most iwlXXXX_apm_init() functions into single iwl_apm_init(). Keep iwl3945_apm_init(), but leverage iwl_apm_init() for most functionality. Update 4965 init sequence to follow most recent factory recommendations. Add following members to struct iwl_cfg to guide the init sequence: pll_cfg_val (replaces needs_pll_cfg), set_l0s, use_bsm Move L0S enable/disable from nic_config() functions to iwl_apm_init(). This satisifies the "FIXME: put here L1A -L0S w/a" notice, and complies with factory-recommended sequence. Add debug info message in iwl_apm_init(), and symmetrical message in iwl_apm_stop(). Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 10 ++- drivers/net/wireless/iwlwifi/iwl-3945.c | 56 ++-------------- drivers/net/wireless/iwlwifi/iwl-4965.c | 56 ++-------------- drivers/net/wireless/iwlwifi/iwl-5000.c | 86 ++++++------------------ drivers/net/wireless/iwlwifi/iwl-6000.c | 42 +++++++++--- drivers/net/wireless/iwlwifi/iwl-core.c | 114 ++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 8 ++- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 8 files changed, 190 insertions(+), 183 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index a00f947bd59c..3da5913225e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -110,7 +110,7 @@ static struct iwl_lib_ops iwl1000_lib = { .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { - .init = iwl5000_apm_init, + .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl1000_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -163,7 +163,9 @@ struct iwl_cfg iwl1000_bgn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = false, + .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, .ht_greenfield_support = true, @@ -186,7 +188,9 @@ struct iwl_cfg iwl1000_bg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = false, + .use_bsm = false, .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.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 9f18b4cba952..7142aa5dbdb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1013,55 +1013,15 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) return rc; } + /* - * Start up NIC's basic functionality after it has been reset - * (e.g. after platform boot, or shutdown via iwl3945_apm_stop()) + * Start up 3945's basic functionality after it has been reset + * (e.g. after platform boot, or shutdown via iwl_apm_stop()) * NOTE: This does not load uCode nor start the embedded processor */ static int iwl3945_apm_init(struct iwl_priv *priv) { - int ret; - - /* Configure chip clock phase-lock-loop */ - iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL); - - /* - * Disable L0S exit timer (platform NMI Work/Around) - * (does this do anything on 3945, or just 4965 and beyond?) - */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - /* Disable L0s without affecting L1; don't wait for ICH (L0s bug W/A) */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - - /* Set FH wait threshold to maximum (HW error during stress W/A) */ - iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); - - /* - * Set "initialization complete" bit to move adapter from - * D0U* --> D0A* (powered-up active) state. - */ - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - /* - * Wait for clock stabilization; once stabilized, access to - * device-internal resources is supported, e.g. iwl_write_prph() - * and accesses to uCode SRAM. - */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret < 0) { - IWL_DEBUG_INFO(priv, "Failed to init the card\n"); - goto out; - } - - /* Enable DMA and BSM clocks, wait for them to stabilize */ - iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); - udelay(20); + int ret = iwl_apm_init(priv); /* Clear APMG (NIC's internal power management) interrupts */ iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); @@ -1072,11 +1032,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv) udelay(5); iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - /* Disable L1-Active */ - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - -out: return ret; } @@ -2876,6 +2831,9 @@ static struct iwl_cfg iwl3945_bg_cfg = { .ops = &iwl3945_ops, .num_of_queues = IWL39_NUM_QUEUES, .mod_params = &iwl3945_mod_params, + .pll_cfg_val = CSR39_ANA_PLL_CFG_VAL, + .set_l0s = false, + .use_bsm = true, .use_isr_legacy = true, .ht_greenfield_support = false, .led_compensation = 64, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1a622aa5a160..32d5f3de429f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -317,64 +317,13 @@ static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask) iwl_write_prph(priv, IWL49_SCD_TXFACT, mask); } -static int iwl4965_apm_init(struct iwl_priv *priv) -{ - int ret = 0; - - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - - /* set "initialization complete" bit to move adapter - * D0U* --> D0A* state */ - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret < 0) { - IWL_DEBUG_INFO(priv, "Failed to init the card\n"); - goto out; - } - - /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); - - udelay(20); - - /* disable L1-Active */ - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - -out: - return ret; -} - - static void iwl4965_nic_config(struct iwl_priv *priv) { unsigned long flags; u16 radio_cfg; - u16 lctl; spin_lock_irqsave(&priv->lock, flags); - lctl = iwl_pcie_link_ctl(priv); - - /* HW bug W/A - negligible power consumption */ - /* L1-ASPM is enabled by BIOS */ - if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) - /* L1-ASPM enabled: disable L0S */ - iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - else - /* L1-ASPM disabled: enable L0S */ - iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); /* write radio config values to register */ @@ -2223,7 +2172,7 @@ static struct iwl_lib_ops iwl4965_lib = { .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .apm_ops = { - .init = iwl4965_apm_init, + .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl4965_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -2276,6 +2225,9 @@ struct iwl_cfg iwl4965_agn_cfg = { .num_of_queues = IWL49_NUM_QUEUES, .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, .mod_params = &iwl4965_mod_params, + .pll_cfg_val = 0, + .set_l0s = true, + .use_bsm = true, .use_isr_legacy = true, .ht_greenfield_support = false, .broken_powersave = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index afa88a304158..a6e347b9799a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -72,72 +72,14 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = { IWL_TX_FIFO_HCCA_2 }; -int iwl5000_apm_init(struct iwl_priv *priv) -{ - int ret = 0; - - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - - /* Set FH wait threshold to maximum (HW error during stress W/A) */ - iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); - - /* enable HAP INTA to move device L1a -> L0s */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); - - if (priv->cfg->need_pll_cfg) - iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); - - /* set "initialization complete" bit to move adapter - * D0U* --> D0A* state */ - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret < 0) { - IWL_DEBUG_INFO(priv, "Failed to init the card\n"); - return ret; - } - - /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); - - udelay(20); - - /* disable L1-Active */ - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - - return ret; -} - /* NIC configuration for 5000 series */ void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; u16 radio_cfg; - u16 lctl; spin_lock_irqsave(&priv->lock, flags); - lctl = iwl_pcie_link_ctl(priv); - - /* HW bug W/A */ - /* L1-ASPM is enabled by BIOS */ - if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) - /* L1-APSM enabled: disable L0S */ - iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - else - /* L1-ASPM disabled: enable L0S */ - iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); /* write radio config values to register */ @@ -1488,7 +1430,7 @@ struct iwl_lib_ops iwl5000_lib = { .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { - .init = iwl5000_apm_init, + .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -1539,7 +1481,7 @@ static struct iwl_lib_ops iwl5150_lib = { .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { - .init = iwl5000_apm_init, + .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -1607,7 +1549,9 @@ struct iwl_cfg iwl5300_agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, @@ -1628,7 +1572,9 @@ struct iwl_cfg iwl5100_bg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, @@ -1649,7 +1595,9 @@ struct iwl_cfg iwl5100_abg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, @@ -1670,7 +1618,9 @@ struct iwl_cfg iwl5100_agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, @@ -1691,7 +1641,9 @@ struct iwl_cfg iwl5350_agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, @@ -1712,7 +1664,9 @@ struct iwl_cfg iwl5150_agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index b53181324487..5211872da880 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -193,7 +193,7 @@ static struct iwl_lib_ops iwl6000_lib = { .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { - .init = iwl5000_apm_init, + .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl6000_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -266,7 +266,9 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -292,7 +294,9 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -317,7 +321,9 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -345,7 +351,9 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -371,7 +379,9 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -396,7 +406,9 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -421,7 +433,9 @@ struct iwl_cfg iwl6050_2agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, @@ -447,7 +461,9 @@ struct iwl_cfg iwl6050_2abg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, @@ -472,7 +488,9 @@ struct iwl_cfg iwl6000_3agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -498,7 +516,9 @@ struct iwl_cfg iwl6050_3agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7ce8663fdb7b..1d7248cd1969 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1369,6 +1369,8 @@ void iwl_apm_stop(struct iwl_priv *priv) { unsigned long flags; + IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n"); + iwl_apm_stop_master(priv); spin_lock_irqsave(&priv->lock, flags); @@ -1382,6 +1384,118 @@ void iwl_apm_stop(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_apm_stop); + +/* + * Start up NIC's basic functionality after it has been reset + * (e.g. after platform boot, or shutdown via iwl_apm_stop()) + * NOTE: This does not load uCode nor start the embedded processor + */ +int iwl_apm_init(struct iwl_priv *priv) +{ + int ret = 0; + u16 lctl; + + IWL_DEBUG_INFO(priv, "Init card's basic functions\n"); + + /* + * Use "set_bit" below rather than "write", to preserve any hardware + * bits already set by default after reset. + */ + + /* Disable L0S exit timer (platform NMI Work/Around) */ + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + + /* + * Disable L0s without affecting L1; + * don't wait for ICH L0s (ICH bug W/A) + */ + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + + /* Set FH wait threshold to maximum (HW error during stress W/A) */ + iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); + + /* + * Enable HAP INTA (interrupt from management bus) to + * wake device's PCI Express link L1a -> L0s + * NOTE: This is no-op for 3945 (non-existant bit) + */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); + + /* + * HW bug W/A - costs negligible power consumption ... + * Check if BIOS (or OS) enabled L1-ASPM on this device + */ + if (priv->cfg->set_l0s) { + lctl = iwl_pcie_link_ctl(priv); + if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == + PCI_CFG_LINK_CTRL_VAL_L1_EN) { + /* L1-ASPM enabled; disable(!) L0S */ + iwl_set_bit(priv, CSR_GIO_REG, + CSR_GIO_REG_VAL_L0S_ENABLED); + IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n"); + } else { + /* L1-ASPM disabled; enable(!) L0S */ + iwl_clear_bit(priv, CSR_GIO_REG, + CSR_GIO_REG_VAL_L0S_ENABLED); + IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n"); + } + } + + /* Configure analog phase-lock-loop before activating to D0A */ + if (priv->cfg->pll_cfg_val) + iwl_set_bit(priv, CSR_ANA_PLL_CFG, priv->cfg->pll_cfg_val); + + /* + * Set "initialization complete" bit to move adapter from + * D0U* --> D0A* (powered-up active) state. + */ + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* + * Wait for clock stabilization; once stabilized, access to + * device-internal resources is supported, e.g. iwl_write_prph() + * and accesses to uCode SRAM. + */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) { + IWL_DEBUG_INFO(priv, "Failed to init the card\n"); + goto out; + } + + /* + * Enable DMA and BSM (if used) clocks, wait for them to stabilize. + * BSM (Boostrap State Machine) is only in 3945 and 4965; + * later devices (i.e. 5000 and later) have non-volatile SRAM, + * and don't need BSM to restore data after power-saving sleep. + * + * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits + * do not disable clocks. This preserves any hardware bits already + * set by default in "CLK_CTRL_REG" after reset. + */ + if (priv->cfg->use_bsm) + iwl_write_prph(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); + else + iwl_write_prph(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + udelay(20); + + /* Disable L1-Active */ + iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + +out: + return ret; +} +EXPORT_SYMBOL(iwl_apm_init); + + + void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a2a580df3d99..a2d526a7b4ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -262,7 +262,12 @@ struct iwl_cfg { const struct iwl_mod_params *mod_params; u8 valid_tx_ant; u8 valid_rx_ant; - bool need_pll_cfg; + + /* for iwl_apm_init() */ + u32 pll_cfg_val; + bool set_l0s; + bool use_bsm; + bool use_isr_legacy; enum iwl_pa_type pa_type; const u16 max_ll_items; @@ -663,6 +668,7 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwl_apm_stop(struct iwl_priv *priv); int iwl_apm_stop_master(struct iwl_priv *priv); +int iwl_apm_init(struct iwl_priv *priv); void iwl_setup_rxon_timing(struct iwl_priv *priv); static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 6ba082d6ab16..1378654801ca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -85,7 +85,6 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags); extern int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp); -extern int iwl5000_apm_init(struct iwl_priv *priv); extern void iwl5000_nic_config(struct iwl_priv *priv); extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv); extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, -- cgit v1.2.3 From 1ed2a3d29ac304092f588a47a9ed2b83d4d8c835 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:22 -0700 Subject: iwlwifi: separate led function from statistic notification Detach led background task from statistic notification routine. if led blinking is required; the blink rate is based on the traffic condition. It do not relate to statistics notification. In addition to that, there is not a requirement for statistics notification has to occur all the time. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 -- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-rx.c | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7142aa5dbdb5..269b9889e39e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -359,8 +359,6 @@ void iwl3945_hw_rx_statistics(struct iwl_priv *priv, le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39)); - - iwl_leds_background(priv); } /****************************************************************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 64d918787e88..a34acb7e44c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1019,6 +1019,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { iwl_rx_handle(priv); priv->isr_stats.rx++; + iwl_leds_background(priv); handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } @@ -1220,6 +1221,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) CSR_INT_PERIODIC_ENA); priv->isr_stats.rx++; + iwl_leds_background(priv); } if (inta & CSR_INT_BIT_FH_TX) { diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 0a407f79de01..cfc31ae4712b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -627,9 +627,6 @@ void iwl_rx_statistics(struct iwl_priv *priv, iwl_rx_calc_noise(priv); queue_work(priv->workqueue, &priv->run_time_calib_work); } - - iwl_leds_background(priv); - if (priv->cfg->ops->lib->temp_ops.temperature && change) priv->cfg->ops->lib->temp_ops.temperature(priv); } -- cgit v1.2.3 From 456d0f76727ba6f97aa1cee63f1bae84642768c4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:23 -0700 Subject: iwlwifi: update bt co-exit configuration parameter Adding parameter ranges for bt co-exist configuration command. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 13 +++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 6 +++--- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 1a7c0d02c19c..0d660a7475a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2218,6 +2218,19 @@ struct iwl_link_quality_cmd { __le32 reserved2; } __attribute__ ((packed)); +#define BT_COEX_DISABLE (0x0) +#define BT_COEX_MODE_2W (0x1) +#define BT_COEX_MODE_3W (0x2) +#define BT_COEX_MODE_4W (0x3) + +#define BT_LEAD_TIME_MIN (0x0) +#define BT_LEAD_TIME_DEF (0x1E) +#define BT_LEAD_TIME_MAX (0xFF) + +#define BT_MAX_KILL_MIN (0x1) +#define BT_MAX_KILL_DEF (0x5) +#define BT_MAX_KILL_MAX (0xFF) + /* * REPLY_BT_CONFIG = 0x9b (command, has simple generic response) * diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1d7248cd1969..77b9825f79ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2003,9 +2003,9 @@ EXPORT_SYMBOL(iwl_isr_legacy); int iwl_send_bt_config(struct iwl_priv *priv) { struct iwl_bt_cmd bt_cmd = { - .flags = 3, - .lead_time = 0xAA, - .max_kill = 1, + .flags = BT_COEX_MODE_4W, + .lead_time = BT_LEAD_TIME_DEF, + .max_kill = BT_MAX_KILL_DEF, .kill_ack_mask = 0, .kill_cts_mask = 0, }; -- cgit v1.2.3 From 52aa081c40324ecb04a47864e4e56dafc5a72a34 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:24 -0700 Subject: iwlwifi: specify the valid tx/rx chain in device config structure Specify both Tx and Rx chain in device configuration structure instead of hard code in set_hw_params() for 4965 Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 32d5f3de429f..bd856df5b04d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -653,10 +653,10 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; - priv->hw_params.tx_chains_num = 2; - priv->hw_params.rx_chains_num = 2; - priv->hw_params.valid_tx_ant = ANT_A | ANT_B; - priv->hw_params.valid_rx_ant = ANT_A | ANT_B; + priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); + priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; + priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; if (priv->cfg->ops->lib->temp_ops.set_ct_kill) priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); @@ -2225,6 +2225,8 @@ struct iwl_cfg iwl4965_agn_cfg = { .num_of_queues = IWL49_NUM_QUEUES, .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, .mod_params = &iwl4965_mod_params, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, .set_l0s = true, .use_bsm = true, -- cgit v1.2.3 From 29b1b2688fd71346f78f175d9669c006686b6dc3 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 23 Oct 2009 13:42:25 -0700 Subject: iwlwifi: fix use after free bug for paged rx In the paged rx patch (4854fde2), I introduced a bug that could possibly touch an already freed page. It is fixed by avoiding the access in this patch. I've also added some comments so that other people touching the code won't make the same mistake. In the future, if we cannot avoid access the page after being handled to the upper layer, we can use get_page/put_page to handle it. For now, it's just not necessary. It also fixed a debug message print bug reported by Stanislaw Gruszka . Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 15 ++++++++++----- drivers/net/wireless/iwlwifi/iwl-agn.c | 11 +++++++++-- drivers/net/wireless/iwlwifi/iwl-rx.c | 21 ++++++++++++++------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 18 +++++++++++++----- 4 files changed, 46 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 269b9889e39e..f5d75288bd27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -548,6 +548,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, u16 len = le16_to_cpu(rx_hdr->len); struct sk_buff *skb; int ret; + __le16 fc = hdr->frame_control; /* We received data from the HW, so stop the watchdog */ if (unlikely(len + IWL39_RX_FRAME_SIZE > @@ -580,9 +581,9 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, /* mac80211 currently doesn't support paged SKB. Convert it to * linear SKB for management frame and data frame requires * software decryption or software defragementation. */ - if (ieee80211_is_mgmt(hdr->frame_control) || - ieee80211_has_protected(hdr->frame_control) || - ieee80211_has_morefrags(hdr->frame_control) || + if (ieee80211_is_mgmt(fc) || + ieee80211_has_protected(fc) || + ieee80211_has_morefrags(fc) || le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) ret = skb_linearize(skb); else @@ -594,11 +595,15 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, goto out; } - iwl_update_stats(priv, false, hdr->frame_control, len); + /* + * XXX: We cannot touch the page and its virtual memory (pkt) after + * here. It might have already been freed by the above skb change. + */ + iwl_update_stats(priv, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); - ieee80211_rx(priv->hw, skb); + ieee80211_rx(priv->hw, skb); out: priv->alloc_rxb_page--; rxb->page = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a34acb7e44c3..0d3886505205 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -814,8 +814,8 @@ void iwl_rx_handle(struct iwl_priv *priv) if (priv->rx_handlers[pkt->hdr.cmd]) { 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]++; + priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); } else { /* No handling needed */ IWL_DEBUG_RX(priv, @@ -824,11 +824,18 @@ void iwl_rx_handle(struct iwl_priv *priv) pkt->hdr.cmd); } + /* + * XXX: After here, we should always check rxb->page + * against NULL before touching it or its virtual + * memory (pkt). Because some rx_handler might have + * already taken or freed the pages. + */ + if (reclaim) { /* Invoke any callbacks, transfer the buffer to caller, * and fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ - if (rxb && rxb->page) + if (rxb->page) iwl_tx_cmd_complete(priv, rxb); else IWL_WARN(priv, "Claim null rxb?\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index cfc31ae4712b..e5339c9ad13e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -241,6 +241,7 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) struct iwl_rx_mem_buffer *rxb; struct page *page; unsigned long flags; + gfp_t gfp_mask = priority; while (1) { spin_lock_irqsave(&rxq->lock, flags); @@ -251,13 +252,13 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) spin_unlock_irqrestore(&rxq->lock, flags); if (rxq->free_count > RX_LOW_WATERMARK) - priority |= __GFP_NOWARN; + gfp_mask |= __GFP_NOWARN; if (priv->hw_params.rx_page_order > 0) - priority |= __GFP_COMP; + gfp_mask |= __GFP_COMP; /* Alloc a new receive buffer */ - page = alloc_pages(priority, priv->hw_params.rx_page_order); + page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order); if (!page) { if (net_ratelimit()) IWL_DEBUG_INFO(priv, "alloc_pages failed, " @@ -922,6 +923,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, { struct sk_buff *skb; int ret = 0; + __le16 fc = hdr->frame_control; /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { @@ -946,9 +948,9 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, /* mac80211 currently doesn't support paged SKB. Convert it to * linear SKB for management frame and data frame requires * software decryption or software defragementation. */ - if (ieee80211_is_mgmt(hdr->frame_control) || - ieee80211_has_protected(hdr->frame_control) || - ieee80211_has_morefrags(hdr->frame_control) || + if (ieee80211_is_mgmt(fc) || + ieee80211_has_protected(fc) || + ieee80211_has_morefrags(fc) || le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) ret = skb_linearize(skb); else @@ -960,7 +962,12 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, goto out; } - iwl_update_stats(priv, false, hdr->frame_control, len); + /* + * XXX: We cannot touch the page and its virtual memory (hdr) after + * here. It might have already been freed by the above skb change. + */ + + iwl_update_stats(priv, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx(priv->hw, skb); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5977a57a234c..8b08bdc10bc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1124,6 +1124,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) struct iwl_rx_mem_buffer *rxb; struct page *page; unsigned long flags; + gfp_t gfp_mask = priority; while (1) { spin_lock_irqsave(&rxq->lock, flags); @@ -1135,13 +1136,13 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) spin_unlock_irqrestore(&rxq->lock, flags); if (rxq->free_count > RX_LOW_WATERMARK) - priority |= __GFP_NOWARN; + gfp_mask |= __GFP_NOWARN; if (priv->hw_params.rx_page_order > 0) - priority |= __GFP_COMP; + gfp_mask |= __GFP_COMP; /* Alloc a new receive buffer */ - page = alloc_pages(priority, priv->hw_params.rx_page_order); + page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order); if (!page) { if (net_ratelimit()) IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n"); @@ -1410,8 +1411,8 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) if (priv->rx_handlers[pkt->hdr.cmd]) { 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]++; + priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); } else { /* No handling needed */ IWL_DEBUG_RX(priv, @@ -1420,11 +1421,18 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) pkt->hdr.cmd); } + /* + * XXX: After here, we should always check rxb->page + * against NULL before touching it or its virtual + * memory (pkt). Because some rx_handler might have + * already taken or freed the pages. + */ + if (reclaim) { /* Invoke any callbacks, transfer the buffer to caller, * and fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ - if (rxb && rxb->page) + if (rxb->page) iwl_tx_cmd_complete(priv, rxb); else IWL_WARN(priv, "Claim null rxb?\n"); -- cgit v1.2.3 From c8c24872c6a90ef0298491a1c14326861ab74cab Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:26 -0700 Subject: iwlwifi: increase max tfd payload size Increase the size of TFD_MAX_PAYLOAD_SIZE (the size of iwl_device_cmd) to accommodate iwl6000_channel_switch_cmd data structure. Signed-off-by: Wey-Yi Guy Acked-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1378654801ca..b520e551f7f8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -364,7 +364,7 @@ enum { CMD_WANT_SKB = (1 << 2), }; -#define IWL_CMD_MAX_PAYLOAD 320 +#define DEF_CMD_PAYLOAD_SIZE 320 /* * IWL_LINK_HDR_MAX should include ieee80211_hdr, radiotap header, @@ -388,7 +388,8 @@ struct iwl_device_cmd { u16 val16; u32 val32; struct iwl_tx_cmd tx; - u8 payload[IWL_CMD_MAX_PAYLOAD]; + struct iwl6000_channel_switch_cmd chswitch; + u8 payload[DEF_CMD_PAYLOAD_SIZE]; } __attribute__ ((packed)) cmd; } __attribute__ ((packed)); @@ -741,7 +742,11 @@ static inline int iwl_queue_used(const struct iwl_queue *q, int i) static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) { - /* This is for scan command, the big buffer at end of command array */ + /* + * This is for init calibration result and scan command which + * required buffer > TFD_MAX_PAYLOAD_SIZE, + * the big buffer at end of command array + */ if (is_huge) return q->n_window; /* must be power of 2 */ -- cgit v1.2.3 From 6047b4f939682ae9bf839fd00c80029cb8f073bb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:27 -0700 Subject: iwlwifi: choose thermal throttle method based on device config Using device configuration structure to decide the type of thermal throttle method for the device. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-power.c | 8 ++------ 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 5211872da880..0873322755aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -277,6 +277,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6000h_2abg_cfg = { @@ -304,6 +305,7 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6000h_2bg_cfg = { @@ -331,6 +333,7 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; /* @@ -362,6 +365,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -389,6 +393,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -416,6 +421,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -444,6 +450,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -471,6 +478,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -499,6 +507,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -527,6 +536,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a2d526a7b4ce..9dbf59811f45 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -225,6 +225,7 @@ struct iwl_mod_params { * The detail algorithm is described in iwl-led.c * @use_rts_for_ht: use rts/cts protection for HT traffic * @chain_noise_num_beacons: number of beacons used to compute chain noise + * @adv_thermal_throttle: support advance thermal throttle * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -278,6 +279,7 @@ struct iwl_cfg { bool use_rts_for_ht; int chain_noise_num_beacons; const bool supports_idle; + bool adv_thermal_throttle; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 150ff87af33b..432f4650cf2e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -893,9 +893,7 @@ void iwl_tt_initialize(struct iwl_priv *priv) 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: + if (priv->cfg->adv_thermal_throttle) { IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n"); tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) * IWL_TI_STATE_MAX, GFP_KERNEL); @@ -928,11 +926,9 @@ void iwl_tt_initialize(struct iwl_priv *priv) &restriction_range[0], size); priv->thermal_throttle.advanced_tt = true; } - break; - default: + } else { IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); priv->thermal_throttle.advanced_tt = false; - break; } } EXPORT_SYMBOL(iwl_tt_initialize); -- cgit v1.2.3 From 480e8407dc0bccdd8d7cfe29b8fcaaa21dd20e68 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:28 -0700 Subject: iwlwifi: issue ct_kill host command based on device config Using device configuration structure to decide how to configure ct_kill host command. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-6000.c | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 9 ++------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ 4 files changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 3da5913225e2..3a645e485dda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -171,6 +171,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl1000_bg_cfg = { @@ -196,6 +197,7 @@ struct iwl_cfg iwl1000_bg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .support_ct_kill_exit = true, }; MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 0873322755aa..f5855293c767 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -278,6 +278,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6000h_2abg_cfg = { @@ -306,6 +307,7 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6000h_2bg_cfg = { @@ -334,6 +336,7 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; /* @@ -366,6 +369,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -394,6 +398,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -422,6 +427,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -451,6 +457,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -479,6 +486,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -508,6 +516,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -537,6 +546,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 77b9825f79ba..e43469cfbbc0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2165,10 +2165,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); priv->thermal_throttle.ct_kill_toggle = false; - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { - case CSR_HW_REV_TYPE_1000: - case CSR_HW_REV_TYPE_6x00: - case CSR_HW_REV_TYPE_6x50: + if (priv->cfg->support_ct_kill_exit) { adv_cmd.critical_temperature_enter = cpu_to_le32(priv->hw_params.ct_kill_threshold); adv_cmd.critical_temperature_exit = @@ -2185,8 +2182,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) "exit is %d\n", priv->hw_params.ct_kill_threshold, priv->hw_params.ct_kill_exit_threshold); - break; - default: + } else { cmd.critical_temperature_R = cpu_to_le32(priv->hw_params.ct_kill_threshold); @@ -2199,7 +2195,6 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) "succeeded, " "critical temperature is %d\n", priv->hw_params.ct_kill_threshold); - break; } } EXPORT_SYMBOL(iwl_rf_kill_ct_config); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 9dbf59811f45..02bacc4975f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -226,6 +226,7 @@ struct iwl_mod_params { * @use_rts_for_ht: use rts/cts protection for HT traffic * @chain_noise_num_beacons: number of beacons used to compute chain noise * @adv_thermal_throttle: support advance thermal throttle + * @support_ct_kill_exit: support ct kill exit condition * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -280,6 +281,7 @@ struct iwl_cfg { int chain_noise_num_beacons; const bool supports_idle; bool adv_thermal_throttle; + bool support_ct_kill_exit; }; /*************************** -- cgit v1.2.3 From 4a56e9652ec2ffce87b099aa2fc5b4eb2d5b2666 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:29 -0700 Subject: iwlwifi: add channel switch support to 5000 series and up Support "channel switch" request by issue "channel switch" host command to uCode. There is no separated "channel switch" indication from mac80211, when detected "IEEE80211_CONF_CHANGE_CHANNEL" flag in iwl_mac_config(), if the station is in "associated" state, then assume "channel switch announcement" IE was received by mac80211. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 6 ------ drivers/net/wireless/iwlwifi/iwl-3945.h | 2 -- drivers/net/wireless/iwlwifi/iwl-4965.c | 12 +++++++----- drivers/net/wireless/iwlwifi/iwl-5000.c | 32 ++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-6000.c | 32 ++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 21 +++++++++++++++++---- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + 7 files changed, 89 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index f5d75288bd27..09a7bd2c0be4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1982,12 +1982,6 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) return 0; } -/* will add 3945 channel switch cmd handling later */ -int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel) -{ - return 0; -} - /** * iwl3945_reg_txpower_periodic - called when time to check our temperature. * diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index f3907c1079f5..964c01980ac0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -280,8 +280,6 @@ extern void iwl3945_config_ap(struct iwl_priv *priv); */ extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid); -extern int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel); - /* * Forward declare iwl-3945.c functions for iwl-base.c */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index bd856df5b04d..1ff465ad40d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1433,14 +1433,13 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) return ret; } -#ifdef IEEE80211_CONF_CHANNEL_SWITCH static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) { int rc; u8 band = 0; bool is_ht40 = false; u8 ctrl_chan_high = 0; - struct iwl4965_channel_switch_cmd cmd = { 0 }; + struct iwl4965_channel_switch_cmd cmd; const struct iwl_channel_info *ch_info; band = priv->band == IEEE80211_BAND_2GHZ; @@ -1461,8 +1460,11 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); if (ch_info) cmd.expect_beacon = is_channel_radar(ch_info); - else - cmd.expect_beacon = 1; + else { + IWL_ERR(priv, "invalid channel switch from %u to %u\n", + priv->active_rxon.channel, channel); + return -EFAULT; + } rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40, ctrl_chan_high, &cmd.tx_power); @@ -1474,7 +1476,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); return rc; } -#endif /** * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array @@ -2171,6 +2172,7 @@ static struct iwl_lib_ops iwl4965_lib = { .load_ucode = iwl4965_load_bsm, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, + .set_channel_switch = iwl4965_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, .stop = iwl_apm_stop, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a6e347b9799a..d256fecc6cda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1382,6 +1382,36 @@ IWL5000_UCODE_GET(init_size); IWL5000_UCODE_GET(init_data_size); IWL5000_UCODE_GET(boot_size); +static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) +{ + struct iwl5000_channel_switch_cmd cmd; + const struct iwl_channel_info *ch_info; + struct iwl_host_cmd hcmd = { + .id = REPLY_CHANNEL_SWITCH, + .len = sizeof(cmd), + .flags = CMD_SIZE_HUGE, + .data = &cmd, + }; + + IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", + priv->active_rxon.channel, channel); + cmd.band = priv->band == IEEE80211_BAND_2GHZ; + cmd.channel = cpu_to_le16(channel); + cmd.rxon_flags = priv->active_rxon.flags; + cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + ch_info = iwl_get_channel_info(priv, priv->band, channel); + if (ch_info) + cmd.expect_beacon = is_channel_radar(ch_info); + else { + IWL_ERR(priv, "invalid channel switch from %u to %u\n", + priv->active_rxon.channel, channel); + return -EFAULT; + } + + return iwl_send_cmd_sync(priv, &hcmd); +} + struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, @@ -1429,6 +1459,7 @@ struct iwl_lib_ops iwl5000_lib = { .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl5000_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, .stop = iwl_apm_stop, @@ -1480,6 +1511,7 @@ static struct iwl_lib_ops iwl5150_lib = { .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl5000_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, .stop = iwl_apm_stop, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index f5855293c767..f5639b47668a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -172,6 +172,37 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) return 0; } +static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) +{ + struct iwl6000_channel_switch_cmd cmd; + const struct iwl_channel_info *ch_info; + struct iwl_host_cmd hcmd = { + .id = REPLY_CHANNEL_SWITCH, + .len = sizeof(cmd), + .flags = CMD_SIZE_HUGE, + .data = &cmd, + }; + + IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", + priv->active_rxon.channel, channel); + + cmd.band = priv->band == IEEE80211_BAND_2GHZ; + cmd.channel = cpu_to_le16(channel); + cmd.rxon_flags = priv->active_rxon.flags; + cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + ch_info = iwl_get_channel_info(priv, priv->band, channel); + if (ch_info) + cmd.expect_beacon = is_channel_radar(ch_info); + else { + IWL_ERR(priv, "invalid channel switch from %u to %u\n", + priv->active_rxon.channel, channel); + return -EFAULT; + } + + return iwl_send_cmd_sync(priv, &hcmd); +} + static struct iwl_lib_ops iwl6000_lib = { .set_hw_params = iwl6000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, @@ -192,6 +223,7 @@ static struct iwl_lib_ops iwl6000_lib = { .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl6000_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, .stop = iwl_apm_stop, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e43469cfbbc0..d2b56baf98fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1284,10 +1284,15 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; struct iwl_csa_notification *csa = &(pkt->u.csa_notif); - IWL_DEBUG_11H(priv, "CSA notif: channel %d, status %d\n", - le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); - rxon->channel = csa->channel; - priv->staging_rxon.channel = csa->channel; + + if (!le32_to_cpu(csa->status)) { + rxon->channel = csa->channel; + priv->staging_rxon.channel = csa->channel; + IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", + le16_to_cpu(csa->channel)); + } else + IWL_ERR(priv, "CSA notif (fail) : channel %d\n", + le16_to_cpu(csa->channel)); } EXPORT_SYMBOL(iwl_rx_csa); @@ -2714,6 +2719,14 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) goto set_ch_out; } + if (iwl_is_associated(priv) && + (le16_to_cpu(priv->active_rxon.channel) != ch) && + priv->cfg->ops->lib->set_channel_switch) { + ret = priv->cfg->ops->lib->set_channel_switch(priv, + ch); + goto out; + } + spin_lock_irqsave(&priv->lock, flags); /* Configure HT40 channels */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 02bacc4975f0..b875dcfca2d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -169,6 +169,7 @@ struct iwl_lib_ops { int (*load_ucode)(struct iwl_priv *priv); void (*dump_nic_event_log)(struct iwl_priv *priv); void (*dump_nic_error_log)(struct iwl_priv *priv); + int (*set_channel_switch)(struct iwl_priv *priv, u16 channel); /* power management */ struct iwl_apm_ops apm_ops; -- cgit v1.2.3 From 6c5cd9d524a3393f6450ee523f4a942d4404f7de Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 23 Oct 2009 13:42:30 -0700 Subject: iwlwifi: remove duplicate defines RX_FREE_BUFFERS and RX_LOW_WATERMARK are currently defined in four places. Based on how files are included we only need the definition in iwl-fh.h Signed-off-by: Reinette Chatre Reported-by: Frans Pop Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-3945.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-dev.h | 6 ------ 3 files changed, 18 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index ccdac69838dd..6fd10d443ba3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -248,12 +248,6 @@ struct iwl3945_eeprom { #define TFD_CTL_PAD_SET(n) (n << 28) #define TFD_CTL_PAD_GET(ctl) (ctl >> 28) -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 64 -#define RX_LOW_WATERMARK 8 - /* Sizes and addresses for instruction and data memory (SRAM) in * 3945's embedded processor. Driver access is via HBUS_TARG_MEM_* regs. */ #define IWL39_RTC_INST_LOWER_BOUND (0x000000) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 964c01980ac0..ebb999a51b58 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -130,12 +130,6 @@ struct iwl3945_frame { #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 64 -#define RX_LOW_WATERMARK 8 - #define SUP_RATE_11A_MAX_NUM_CHANNELS 8 #define SUP_RATE_11B_MAX_NUM_CHANNELS 4 #define SUP_RATE_11G_MAX_NUM_CHANNELS 12 diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b520e551f7f8..e7ce67387662 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -407,12 +407,6 @@ struct iwl_host_cmd { u8 id; }; -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 64 -#define RX_LOW_WATERMARK 8 - #define SUP_RATE_11A_MAX_NUM_CHANNELS 8 #define SUP_RATE_11B_MAX_NUM_CHANNELS 4 #define SUP_RATE_11G_MAX_NUM_CHANNELS 12 -- cgit v1.2.3 From 71c55d90f9733abdf5e4e0bc24f71e189cefeea6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:31 -0700 Subject: iwlwifi: remove unused parameters parameters "len" is not used in both iwl_tx_queue_free() and iwl_cmd_queue_free() functions Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 5c43d7c43b30..8ae4c9b614e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -131,7 +131,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; - int i, len; + int i; if (q->n_bd == 0) return; @@ -141,8 +141,6 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) priv->cfg->ops->lib->txq_free_tfd(priv, txq); - len = sizeof(struct iwl_device_cmd) * q->n_window; - /* De-alloc array of command/tx buffers */ for (i = 0; i < TFD_TX_CMD_SLOTS; i++) kfree(txq->cmd[i]); @@ -180,14 +178,11 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; - int i, len; + int i; if (q->n_bd == 0) return; - len = sizeof(struct iwl_device_cmd) * q->n_window; - len += IWL_MAX_SCAN_SIZE; - /* De-alloc array of command/tx buffers */ for (i = 0; i <= TFD_CMD_SLOTS; i++) kfree(txq->cmd[i]); -- cgit v1.2.3 From 7300515d1095aa11731866da7c9b000f2edb4626 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 23 Oct 2009 13:42:32 -0700 Subject: iwlwifi: reuse page for notification packets For notification packets and SKBs that fail to rx correctly, add them back into the rx_free list so that the pages can be reused later. This avoids allocating new rx pages unnecessarily. Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 27 +++++++++++++++------------ drivers/net/wireless/iwlwifi/iwl3945-base.c | 27 +++++++++++++++------------ 2 files changed, 30 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0d3886505205..ea1b9315f17c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -769,7 +769,7 @@ void iwl_rx_handle(struct iwl_priv *priv) IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); /* calculate total frames need to be restock after handling RX */ - total_empty = r - priv->rxq.write_actual; + total_empty = r - rxq->write_actual; if (total_empty < 0) total_empty += RX_QUEUE_SIZE; @@ -841,25 +841,28 @@ void iwl_rx_handle(struct iwl_priv *priv) IWL_WARN(priv, "Claim null rxb?\n"); } - /* For now we just don't re-use anything. We can tweak this - * later to try and re-use notification packets and SKBs that - * fail to Rx correctly */ + /* Reuse the page if possible. For notification packets and + * SKBs that fail to Rx correctly, add them back into the + * rx_free list for reuse later. */ + spin_lock_irqsave(&rxq->lock, flags); if (rxb->page != NULL) { - priv->alloc_rxb_page--; - __free_pages(rxb->page, priv->hw_params.rx_page_order); - rxb->page = NULL; - } + rxb->page_dma = pci_map_page(priv->pci_dev, rxb->page, + 0, PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } else + list_add_tail(&rxb->list, &rxq->rx_used); - spin_lock_irqsave(&rxq->lock, flags); - list_add_tail(&rxb->list, &priv->rxq.rx_used); spin_unlock_irqrestore(&rxq->lock, flags); + i = (i + 1) & RX_QUEUE_MASK; /* If there are a lot of unused frames, * restock the Rx queue so ucode wont assert. */ if (fill_rx) { count++; if (count >= 8) { - priv->rxq.read = i; + rxq->read = i; iwl_rx_replenish_now(priv); count = 0; } @@ -867,7 +870,7 @@ void iwl_rx_handle(struct iwl_priv *priv) } /* Backtrack one entry */ - priv->rxq.read = i; + rxq->read = i; if (fill_rx) iwl_rx_replenish_now(priv); else diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8b08bdc10bc9..9a430eed34ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1367,7 +1367,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) i = rxq->read; /* calculate total frames need to be restock after handling RX */ - total_empty = r - priv->rxq.write_actual; + total_empty = r - rxq->write_actual; if (total_empty < 0) total_empty += RX_QUEUE_SIZE; @@ -1438,25 +1438,28 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) IWL_WARN(priv, "Claim null rxb?\n"); } - /* For now we just don't re-use anything. We can tweak this - * later to try and re-use notification packets and SKBs that - * fail to Rx correctly */ + /* Reuse the page if possible. For notification packets and + * SKBs that fail to Rx correctly, add them back into the + * rx_free list for reuse later. */ + spin_lock_irqsave(&rxq->lock, flags); if (rxb->page != NULL) { - priv->alloc_rxb_page--; - __free_pages(rxb->page, priv->hw_params.rx_page_order); - rxb->page = NULL; - } + rxb->page_dma = pci_map_page(priv->pci_dev, rxb->page, + 0, PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } else + list_add_tail(&rxb->list, &rxq->rx_used); - spin_lock_irqsave(&rxq->lock, flags); - list_add_tail(&rxb->list, &priv->rxq.rx_used); spin_unlock_irqrestore(&rxq->lock, flags); + i = (i + 1) & RX_QUEUE_MASK; /* If there are a lot of unused frames, * restock the Rx queue so ucode won't assert. */ if (fill_rx) { count++; if (count >= 8) { - priv->rxq.read = i; + rxq->read = i; iwl3945_rx_replenish_now(priv); count = 0; } @@ -1464,7 +1467,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) } /* Backtrack one entry */ - priv->rxq.read = i; + rxq->read = i; if (fill_rx) iwl3945_rx_replenish_now(priv); else -- cgit v1.2.3 From 570af86e0ab7e7b42b2562ff3209c16ab1ebd5f8 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:33 -0700 Subject: iwlwifi: remove duplicated define Duplicated define for listen interval (IWL_CONN_MAX_LISTEN_INTERVAL and IWL_CONN_LISTEN_INTERVAL), remove IWL_CONN_LISTEN_INTERVAL Signed-off-by: Wey-Yi Guy Reported-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-power.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-power.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 432f4650cf2e..9bce2c1625e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -163,9 +163,9 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); - if (slp_itrvl > IWL_CONN_LISTEN_INTERVAL) + if (slp_itrvl > IWL_CONN_MAX_LISTEN_INTERVAL) cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = - cpu_to_le32(IWL_CONN_LISTEN_INTERVAL); + cpu_to_le32(IWL_CONN_MAX_LISTEN_INTERVAL); /* enforce max sleep interval */ for (i = IWL_POWER_VEC_SIZE - 1; i >= 0 ; i--) { diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 0755518f86e1..310c32e8f698 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -30,8 +30,6 @@ #include "iwl-commands.h" -#define IWL_CONN_LISTEN_INTERVAL 10 - #define IWL_ABSOLUTE_ZERO 0 #define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 -- cgit v1.2.3 From 442464218d93aa0aacc55c3a7ac908ae00abff5f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:34 -0700 Subject: iwlwifi: update lowest API version support for 6x00 & 6x50 series For 6x00 and 6x50 series devices, APIv4 is the lowest firmware version driver can support. This is also the lowest API version available to the public so there is no need for backward compatibility support for the earlier API versions. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index f5639b47668a..32466d38d1ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -52,8 +52,8 @@ #define IWL6050_UCODE_API_MAX 4 /* Lowest firmware API version supported */ -#define IWL6000_UCODE_API_MIN 1 -#define IWL6050_UCODE_API_MIN 1 +#define IWL6000_UCODE_API_MIN 4 +#define IWL6050_UCODE_API_MIN 4 #define IWL6000_FW_PRE "iwlwifi-6000-" #define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" -- cgit v1.2.3 From c166b25a5c02d881b1da15f3afe9dc9e56b206a8 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 23 Oct 2009 13:42:35 -0700 Subject: iwlwifi: make sure device is reset when unloading driver Add unconditional call to apm_ops.stop() to reset device to low power state when unloading driver. Some paths have existed to unload driver *without* resetting device, therefore some errors have persisted through multiple load/unload cycles, until the whole platform gets rebooted; this is an attempt to remedy some of those situations. Sorry, I can't seem to find a bughost.org bug that specifically has these symptoms, but I had it happen recently here. Note that this will *not* fix situations in which the PCI express bus has crashed (evidenced by register reads showing "0xffffffff"), e.g. bughost.org 1855 and 2096; device is unreachable from driver in those cases. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 9 +++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 9 +++++++++ 2 files changed, 18 insertions(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ea1b9315f17c..fa1672e99e4b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3256,6 +3256,15 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_down(priv); } + /* + * Make sure device is reset to low power before unloading driver. + * This may be redundant with iwl_down(), but there are paths to + * run iwl_down() without calling apm_ops.stop(), and there are + * paths to avoid running iwl_down() at all before leaving driver. + * This (inexpensive) call *makes sure* device is reset. + */ + priv->cfg->ops->lib->apm_ops.stop(priv); + iwl_tt_exit(priv); /* make sure we flush any pending irq or diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 9a430eed34ad..bfd7f497157f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4135,6 +4135,15 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_down(priv); } + /* + * Make sure device is reset to low power before unloading driver. + * This may be redundant with iwl_down(), but there are paths to + * run iwl_down() without calling apm_ops.stop(), and there are + * paths to avoid running iwl_down() at all before leaving driver. + * This (inexpensive) call *makes sure* device is reset. + */ + priv->cfg->ops->lib->apm_ops.stop(priv); + /* make sure we flush any pending irq or * tasklet for the driver */ -- cgit v1.2.3 From d23000cd8992823e06ca0745564f2c25fe923ce4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:36 -0700 Subject: iwlwifi: minor comments changes for wimax co-exist command 'COEX_PRIORITY_TABLE_CMD' host command will be supported for 5000 series and up. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 0d660a7475a0..954bad60355d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -109,7 +109,7 @@ enum { REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ /* WiMAX coexistence */ - COEX_PRIORITY_TABLE_CMD = 0x5a, /*5000 only */ + COEX_PRIORITY_TABLE_CMD = 0x5a, /* for 5000 series and up */ COEX_MEDIUM_NOTIFICATION = 0x5b, COEX_EVENT_CMD = 0x5c, -- cgit v1.2.3 From 133d7c6a504c672011ebc24b26e05b15f7410c07 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 28 Oct 2009 16:29:30 -0400 Subject: wireless: remove WLAN_80211 and WLAN_PRE80211 from Kconfig With the WLAN_PRE80211 drivers moved to drivers/staging, this distinction becomes unnecessary. Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 48 ++++++++++--------------------- drivers/net/wireless/ath/Kconfig | 1 - drivers/net/wireless/ath/ar9170/Kconfig | 2 +- drivers/net/wireless/ath/ath5k/Kconfig | 2 +- drivers/net/wireless/ath/ath9k/Kconfig | 2 +- drivers/net/wireless/b43/Kconfig | 2 +- drivers/net/wireless/b43legacy/Kconfig | 2 +- drivers/net/wireless/hostap/Kconfig | 1 - drivers/net/wireless/ipw2x00/Kconfig | 6 ++-- drivers/net/wireless/iwlwifi/Kconfig | 2 +- drivers/net/wireless/iwmc3200wifi/Kconfig | 2 +- drivers/net/wireless/libertas/Kconfig | 2 +- drivers/net/wireless/orinoco/Kconfig | 2 +- drivers/net/wireless/p54/Kconfig | 2 +- drivers/net/wireless/rt2x00/Kconfig | 2 +- drivers/net/wireless/wl12xx/Kconfig | 2 +- drivers/net/wireless/zd1211rw/Kconfig | 2 +- 17 files changed, 31 insertions(+), 51 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index bf0eb4e774b4..674a08b07884 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -16,27 +16,9 @@ menuconfig WLAN if WLAN -menuconfig WLAN_PRE80211 - bool "Wireless LAN (pre-802.11)" - depends on NETDEVICES - ---help--- - Say Y if you have any pre-802.11 wireless LAN hardware. - - This option does not affect the kernel build, it only - lets you choose drivers. - -menuconfig WLAN_80211 - bool "Wireless LAN (IEEE 802.11)" - depends on NETDEVICES - ---help--- - Say Y if you have any 802.11 wireless LAN hardware. - - This option does not affect the kernel build, it only - lets you choose drivers. - config PCMCIA_RAYCS tristate "Aviator/Raytheon 2.4GHz wireless support" - depends on PCMCIA && WLAN_80211 + depends on PCMCIA select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV @@ -51,7 +33,7 @@ config PCMCIA_RAYCS config LIBERTAS_THINFIRM tristate "Marvell 8xxx Libertas WLAN driver support with thin firmware" - depends on WLAN_80211 && MAC80211 + depends on MAC80211 select FW_LOADER ---help--- A library for Marvell Libertas 8xxx devices using thinfirm. @@ -64,7 +46,7 @@ config LIBERTAS_THINFIRM_USB config AIRO tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" - depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN) + depends on ISA_DMA_API && (PCI || BROKEN) select WIRELESS_EXT select CRYPTO select WEXT_SPY @@ -84,7 +66,7 @@ config AIRO config ATMEL tristate "Atmel at76c50x chipset 802.11b support" - depends on (PCI || PCMCIA) && WLAN_80211 + depends on (PCI || PCMCIA) select WIRELESS_EXT select WEXT_PRIV select FW_LOADER @@ -119,7 +101,7 @@ config PCMCIA_ATMEL config AT76C50X_USB tristate "Atmel at76c503/at76c505/at76c505a USB cards" - depends on MAC80211 && WLAN_80211 && USB + depends on MAC80211 && USB select FW_LOADER ---help--- Enable support for USB Wireless devices using Atmel at76c503, @@ -127,7 +109,7 @@ config AT76C50X_USB config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" - depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211 + depends on PCMCIA && (BROKEN || !M32R) select WIRELESS_EXT select CRYPTO select CRYPTO_AES @@ -147,7 +129,7 @@ config AIRO_CS config PCMCIA_WL3501 tristate "Planet WL3501 PCMCIA cards" - depends on EXPERIMENTAL && PCMCIA && WLAN_80211 + depends on EXPERIMENTAL && PCMCIA select WIRELESS_EXT select WEXT_SPY help @@ -157,7 +139,7 @@ config PCMCIA_WL3501 config PRISM54 tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' - depends on PCI && EXPERIMENTAL && WLAN_80211 + depends on PCI && EXPERIMENTAL select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV @@ -181,7 +163,7 @@ config PRISM54 config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" - depends on USB && WLAN_80211 + depends on USB select WIRELESS_EXT select WEXT_PRIV select FW_LOADER @@ -200,7 +182,7 @@ config USB_ZD1201 config USB_NET_RNDIS_WLAN tristate "Wireless RNDIS USB support" - depends on USB && WLAN_80211 && EXPERIMENTAL + depends on USB && EXPERIMENTAL depends on CFG80211 select USB_USBNET select USB_NET_CDCETHER @@ -228,7 +210,7 @@ config USB_NET_RNDIS_WLAN config RTL8180 tristate "Realtek 8180/8185 PCI support" - depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && PCI && EXPERIMENTAL select EEPROM_93CX6 ---help--- This is a driver for RTL8180 and RTL8185 based cards. @@ -284,7 +266,7 @@ config RTL8180 config RTL8187 tristate "Realtek 8187 and 8187B USB support" - depends on MAC80211 && USB && WLAN_80211 + depends on MAC80211 && USB select EEPROM_93CX6 ---help--- This is a driver for RTL8187 and RTL8187B based cards. @@ -313,7 +295,7 @@ config RTL8187_LEDS config ADM8211 tristate "ADMtek ADM8211 support" - depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && PCI && EXPERIMENTAL select CRC32 select EEPROM_93CX6 ---help--- @@ -340,7 +322,7 @@ config ADM8211 config MAC80211_HWSIM tristate "Simulated radio testing tool for mac80211" - depends on MAC80211 && WLAN_80211 + depends on MAC80211 ---help--- This driver is a developer testing tool that can be used to test IEEE 802.11 networking stack (mac80211) functionality. This is not @@ -353,7 +335,7 @@ config MAC80211_HWSIM config MWL8K tristate "Marvell 88W8xxx PCI/PCIe Wireless support" - depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && PCI && EXPERIMENTAL ---help--- This driver supports Marvell TOPDOG 802.11 wireless cards. diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 6ce86cb37654..4e7a7fd695c8 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,6 +1,5 @@ menuconfig ATH_COMMON tristate "Atheros Wireless Cards" - depends on WLAN_80211 depends on CFG80211 ---help--- This will enable the support for the Atheros wireless drivers. diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig index 05918f1e685a..d7a4799d20fb 100644 --- a/drivers/net/wireless/ath/ar9170/Kconfig +++ b/drivers/net/wireless/ath/ar9170/Kconfig @@ -1,6 +1,6 @@ config AR9170_USB tristate "Atheros AR9170 802.11n USB support" - depends on USB && MAC80211 && WLAN_80211 + depends on USB && MAC80211 select FW_LOADER help This is a driver for the Atheros "otus" 802.11n USB devices. diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 06d006675d7d..eb83b7b4d0e3 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -1,6 +1,6 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" - depends on PCI && MAC80211 && WLAN_80211 + depends on PCI && MAC80211 select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 99ce066392a7..b735fb399fb1 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -3,7 +3,7 @@ config ATH9K_HW config ATH9K tristate "Atheros 802.11n wireless cards support" - depends on PCI && MAC80211 && WLAN_80211 + depends on PCI && MAC80211 select ATH9K_HW select MAC80211_LEDS select LEDS_CLASS diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 54ea61c15d8b..64c12e1bced3 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -1,6 +1,6 @@ config B43 tristate "Broadcom 43xx wireless support (mac80211 stack)" - depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA + depends on SSB_POSSIBLE && MAC80211 && HAS_DMA select SSB select FW_LOADER ---help--- diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index 94a463478053..1ffa28835c58 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -1,6 +1,6 @@ config B43LEGACY tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)" - depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA + depends on SSB_POSSIBLE && MAC80211 && HAS_DMA select SSB select FW_LOADER ---help--- diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig index 08f1e989653d..287d82728bc3 100644 --- a/drivers/net/wireless/hostap/Kconfig +++ b/drivers/net/wireless/hostap/Kconfig @@ -1,6 +1,5 @@ config HOSTAP tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" - depends on WLAN_80211 select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index 59ec9eec5024..2715b101aded 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -4,7 +4,7 @@ config IPW2100 tristate "Intel PRO/Wireless 2100 Network Connection" - depends on PCI && WLAN_80211 && CFG80211 + depends on PCI && CFG80211 select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV @@ -65,7 +65,7 @@ config IPW2100_DEBUG config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && WLAN_80211 && CFG80211 && CFG80211_WEXT + depends on PCI && CFG80211 && CFG80211_WEXT select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV @@ -154,7 +154,7 @@ config IPW2200_DEBUG config LIBIPW tristate - depends on PCI && WLAN_80211 && CFG80211 + depends on PCI && CFG80211 select WIRELESS_EXT select WEXT_SPY select CRYPTO diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index c82c97be7bfa..b16b06c2031f 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -1,6 +1,6 @@ config IWLWIFI tristate "Intel Wireless Wifi" - depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on PCI && MAC80211 && EXPERIMENTAL select FW_LOADER config IWLWIFI_SPECTRUM_MEASUREMENT diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig index 9606b3100fde..b9d34a766964 100644 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -1,6 +1,6 @@ config IWM tristate "Intel Wireless Multicomm 3200 WiFi driver" - depends on MMC && WLAN_80211 && EXPERIMENTAL + depends on MMC && EXPERIMENTAL depends on CFG80211 select FW_LOADER select IWMC3200TOP diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig index 8f8d75b61ea9..30aa9d48d67e 100644 --- a/drivers/net/wireless/libertas/Kconfig +++ b/drivers/net/wireless/libertas/Kconfig @@ -1,6 +1,6 @@ config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" - depends on WLAN_80211 && CFG80211 + depends on CFG80211 select WIRELESS_EXT select WEXT_SPY select LIB80211 diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig index dce652054afd..e2a2c18920aa 100644 --- a/drivers/net/wireless/orinoco/Kconfig +++ b/drivers/net/wireless/orinoco/Kconfig @@ -1,6 +1,6 @@ config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" - depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 + depends on (PPC_PMAC || PCI || PCMCIA) depends on CFG80211 && CFG80211_WEXT select WIRELESS_EXT select WEXT_SPY diff --git a/drivers/net/wireless/p54/Kconfig b/drivers/net/wireless/p54/Kconfig index b45d6a4ed1e8..b0342a520bf1 100644 --- a/drivers/net/wireless/p54/Kconfig +++ b/drivers/net/wireless/p54/Kconfig @@ -1,6 +1,6 @@ config P54_COMMON tristate "Softmac Prism54 support" - depends on MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && EXPERIMENTAL select FW_LOADER ---help--- This is common code for isl38xx/stlc45xx based modules. diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 390c0c7b3ac2..a6796a130486 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -1,6 +1,6 @@ menuconfig RT2X00 tristate "Ralink driver support" - depends on MAC80211 && WLAN_80211 + depends on MAC80211 ---help--- This will enable the support for the Ralink drivers, developed in the rt2x00 project . diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 88060e117541..33de7fa4f882 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -1,6 +1,6 @@ menuconfig WL12XX tristate "TI wl12xx driver support" - depends on MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && EXPERIMENTAL ---help--- This will enable TI wl12xx driver support. The drivers make use of the mac80211 stack. diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig index 74b31eafe72d..5f809695f71a 100644 --- a/drivers/net/wireless/zd1211rw/Kconfig +++ b/drivers/net/wireless/zd1211rw/Kconfig @@ -1,6 +1,6 @@ config ZD1211RW tristate "ZyDAS ZD1211/ZD1211B USB-wireless support" - depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on USB && MAC80211 && EXPERIMENTAL select FW_LOADER ---help--- This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless -- cgit v1.2.3 From 5ebeb5a676c864acf59caa166b3cc0a13b7cff93 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:04 -0700 Subject: iwlwifi: provide firmware version By setting the firmware version in wiphy it is possible to obtain this information via ethtool. Some examples, # ethtool -i wlan1 driver: iwlagn version: 2.6.32-rc5-wl-56840-g26d8540 firmware-version: 228.57.2.23 bus-info: 0000:03:00.0 # ethtool -i wlan0 driver: iwl3945 version: 2.6.32-rc5-wl-56840-g26d8540 firmware-version: 15.28.2.8 bus-info: 0000:02:00.0 Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 8 ++++++++ 2 files changed, 16 insertions(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index fa1672e99e4b..05d1070e22d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1377,6 +1377,14 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_UCODE_API(priv->ucode_ver), IWL_UCODE_SERIAL(priv->ucode_ver)); + snprintf(priv->hw->wiphy->fw_version, + sizeof(priv->hw->wiphy->fw_version), + "%u.%u.%u.%u", + IWL_UCODE_MAJOR(priv->ucode_ver), + IWL_UCODE_MINOR(priv->ucode_ver), + IWL_UCODE_API(priv->ucode_ver), + IWL_UCODE_SERIAL(priv->ucode_ver)); + if (build) IWL_DEBUG_INFO(priv, "Build %u\n", build); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index bfd7f497157f..5c80a83eb2e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2160,6 +2160,14 @@ static int iwl3945_read_ucode(struct iwl_priv *priv) IWL_UCODE_API(priv->ucode_ver), IWL_UCODE_SERIAL(priv->ucode_ver)); + snprintf(priv->hw->wiphy->fw_version, + sizeof(priv->hw->wiphy->fw_version), + "%u.%u.%u.%u", + IWL_UCODE_MAJOR(priv->ucode_ver), + IWL_UCODE_MINOR(priv->ucode_ver), + IWL_UCODE_API(priv->ucode_ver), + IWL_UCODE_SERIAL(priv->ucode_ver)); + IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", priv->ucode_ver); IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n", -- cgit v1.2.3 From 5220af0c3b44f5d6e32661e5bb49154c514dbf4f Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 30 Oct 2009 14:36:05 -0700 Subject: iwlwifi: remove unneeded locks from apm_stop() and stop_master() Since priv->reg_lock was added to keep multi-access register manipulation atomic, priv->lock protection is no longer needed. Remove this from iwl_apm_stop_master() and iwl_apm_stop(). Add warning of timeout when polling for busmaster disablement confirmation, and some comments. NOTE: This is needed to enable use of apm_ops.stop() within iwl_eeprom_init(); priv->lock does not get initialized until after this flow. See patch "remove power-wasting calls to apm_ops.init()" Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d2b56baf98fb..4808f6661160 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1353,39 +1353,39 @@ EXPORT_SYMBOL(iwl_irq_handle_error); int iwl_apm_stop_master(struct iwl_priv *priv) { - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); + int ret = 0; - /* set stop master bit */ + /* stop device's busmaster DMA activity */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, + ret = iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (ret) + IWL_WARN(priv, "Master Disable Timed Out, 100 usec\n"); - spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO(priv, "stop master\n"); - return 0; + return ret; } EXPORT_SYMBOL(iwl_apm_stop_master); void iwl_apm_stop(struct iwl_priv *priv) { - unsigned long flags; - IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n"); + /* Stop device's DMA activity */ iwl_apm_stop_master(priv); - spin_lock_irqsave(&priv->lock, flags); - + /* Reset the entire device */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); - /* clear "init complete" move adapter D0A* --> D0U state */ + + /* + * Clear "initialization complete" bit to move adapter from + * D0A* (powered-up Active) --> D0U* (Uninitialized) state. + */ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - spin_unlock_irqrestore(&priv->lock, flags); } EXPORT_SYMBOL(iwl_apm_stop); -- cgit v1.2.3 From 88521364cc04b67f36748983545b9fe1d4ba4a15 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 30 Oct 2009 14:36:06 -0700 Subject: iwlwifi: remove power-wasting calls to apm_ops.init() To save power, don't run apm_ops.init() until needed at "up" time. EEPROM (5000 and earlier devices) may be read without running apm_ops.init(), but OTP reads (6000 and newer devices) require a powered-up chip. Therefore, remove apm_ops.init() from the general path in XXXX_pci_probe(), and call it only if device uses OTP. Once done with OTP read, call apm_ops.stop() to reset chip and save power until "up" time comes around. NOTE: This patch depends on removal of priv->lock from iwl_apm_stop(); lock does not get initialized until later in flow. See patch "remove unneeded locks from apm_stop()". Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ------ drivers/net/wireless/iwlwifi/iwl-eeprom.c | 11 +++++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 7 ------- 3 files changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 05d1070e22d0..6daaad1e4bc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3113,12 +3113,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_iounmap; } - /* amp init */ - err = priv->cfg->ops->lib->apm_ops.init(priv); - if (err < 0) { - IWL_ERR(priv, "Failed to init APMG\n"); - goto out_iounmap; - } /***************** * 4. Read EEPROM *****************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 9429cb1c69bd..8a0709e81a9f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -533,6 +533,10 @@ int iwl_eeprom_init(struct iwl_priv *priv) goto err; } if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { + + /* OTP reads require powered-up chip */ + priv->cfg->ops->lib->apm_ops.init(priv); + ret = iwl_init_otp_access(priv); if (ret) { IWL_ERR(priv, "Failed to initialize OTP access.\n"); @@ -563,6 +567,13 @@ int iwl_eeprom_init(struct iwl_priv *priv) e[cache_addr / 2] = eeprom_data; cache_addr += sizeof(u16); } + + /* + * Now that OTP reads are complete, reset chip to save + * power until we load uCode during "up". + */ + priv->cfg->ops->lib->apm_ops.stop(priv); + } else { /* eeprom is an array of 16bit values */ for (addr = 0; addr < sz; addr += sizeof(u16)) { diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5c80a83eb2e1..23b31e6dcacd 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4000,13 +4000,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e */ spin_lock_init(&priv->reg_lock); - /* amp init */ - err = priv->cfg->ops->lib->apm_ops.init(priv); - if (err < 0) { - IWL_DEBUG_INFO(priv, "Failed to init the card\n"); - goto out_iounmap; - } - /*********************** * 4. Read EEPROM * ********************/ -- cgit v1.2.3 From a6c5c731c3f783f60ed79dcf41efa8b5b3af2f22 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 30 Oct 2009 14:36:07 -0700 Subject: iwlagn: invoke L0S workaround for 6000/1000 series Invoke workaround to avoid instability in L0->L0S->L1 transition on PCIe bus. Workaround disables L0S state so device moves directly from L0->L1. Workaround needed on all devices since and including 4965; add to 6000/1000. Describe bug and workaround better in comments. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 20 ++++++++++---------- drivers/net/wireless/iwlwifi/iwl-core.c | 8 ++++++-- 3 files changed, 18 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 3a645e485dda..1e387b9dce1e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -164,7 +164,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, @@ -190,7 +190,7 @@ struct iwl_cfg iwl1000_bg_cfg = { .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 32466d38d1ae..2f841a8576e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -299,7 +299,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -329,7 +329,7 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -358,7 +358,7 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -390,7 +390,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -420,7 +420,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -449,7 +449,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -478,7 +478,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, @@ -508,7 +508,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, @@ -537,7 +537,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -567,7 +567,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 4808f6661160..addc9ad5a5c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1430,8 +1430,12 @@ int iwl_apm_init(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); /* - * HW bug W/A - costs negligible power consumption ... - * Check if BIOS (or OS) enabled L1-ASPM on this device + * HW bug W/A for instability in PCIe bus L0->L0S->L1 transition. + * Check if BIOS (or OS) enabled L1-ASPM on this device. + * If so (likely), disable L0S, so device moves directly L0->L1; + * costs negligible amount of power savings. + * If not (unlikely), enable L0S, so there is at least some + * power savings, even without L1. */ if (priv->cfg->set_l0s) { lctl = iwl_pcie_link_ctl(priv); -- cgit v1.2.3 From c72cd19fab7983e97a1a41b7158e0b9f87a7fe96 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 30 Oct 2009 14:36:08 -0700 Subject: iwlagn: Clarify FH_TX interrupt Add/clarify comments and debug messages for interrupt used only for uCode load Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6daaad1e4bc9..7751a75d4dc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1033,11 +1033,12 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } + /* This "Tx" DMA channel is used only for loading uCode */ if (inta & CSR_INT_BIT_FH_TX) { - IWL_DEBUG_ISR(priv, "Tx interrupt\n"); + IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); priv->isr_stats.tx++; handled |= CSR_INT_BIT_FH_TX; - /* FH finished to write, send event */ + /* Wake up uCode load routine, now that load is complete */ priv->ucode_write_complete = 1; wake_up_interruptible(&priv->wait_command_queue); } @@ -1234,12 +1235,13 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) iwl_leds_background(priv); } + /* This "Tx" DMA channel is used only for loading uCode */ if (inta & CSR_INT_BIT_FH_TX) { iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK); - IWL_DEBUG_ISR(priv, "Tx interrupt\n"); + IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); priv->isr_stats.tx++; handled |= CSR_INT_BIT_FH_TX; - /* FH finished to write, send event */ + /* Wake up uCode load routine, now that load is complete */ priv->ucode_write_complete = 1; wake_up_interruptible(&priv->wait_command_queue); } -- cgit v1.2.3 From c2e61da29d92df864dc5eec81d774199b02d7023 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 30 Oct 2009 14:36:09 -0700 Subject: iwlagn: update write pointers for all tx queues after wakeup Wakeup interrupt has been updating write pointers (indexes, actually) only for tx queues 0-5. This is adequate just for 3945, but inadequate for other devices, all of which have more tx queues. Now updating all tx/command queues, so device can be aware of all new tx and host commands enqueued while device was asleep. This can potentially improve data traffic bandwidth and/or latency. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7751a75d4dc9..0cb95bfd15a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -890,6 +890,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) u32 inta, handled = 0; u32 inta_fh; unsigned long flags; + u32 i; #ifdef CONFIG_IWLWIFI_DEBUG u32 inta_mask; #endif @@ -1007,19 +1008,17 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) handled |= CSR_INT_BIT_SW_ERR; } - /* uCode wakes up after power-down sleep */ + /* + * uCode wakes up after power-down sleep. + * Tell device about any new tx or host commands enqueued, + * and about any Rx buffers made available while asleep. + */ if (inta & CSR_INT_BIT_WAKEUP) { IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - iwl_txq_update_write_ptr(priv, &priv->txq[0]); - iwl_txq_update_write_ptr(priv, &priv->txq[1]); - iwl_txq_update_write_ptr(priv, &priv->txq[2]); - iwl_txq_update_write_ptr(priv, &priv->txq[3]); - iwl_txq_update_write_ptr(priv, &priv->txq[4]); - iwl_txq_update_write_ptr(priv, &priv->txq[5]); - + for (i = 0; i < priv->hw_params.max_txq_num; i++) + iwl_txq_update_write_ptr(priv, &priv->txq[i]); priv->isr_stats.wakeup++; - handled |= CSR_INT_BIT_WAKEUP; } -- cgit v1.2.3 From c33de6256a07869b48830e3a26fb6942ea8c4f79 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:10 -0700 Subject: iwlwifi: unmap memory before use Handling responses to driver originated commands include passing the original command buffer to the caller. At this time it is possible for a callback to be invoked that is passed this command buffer and thus likely to access it. We need to make sure that the memory associated with that buffer is not DMA mapped at the time. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 8ae4c9b614e7..b46967ff3806 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1121,11 +1121,6 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, return; } - pci_unmap_single(priv->pci_dev, - pci_unmap_addr(&txq->meta[cmd_idx], mapping), - pci_unmap_len(&txq->meta[cmd_idx], len), - PCI_DMA_BIDIRECTIONAL); - for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { @@ -1173,6 +1168,11 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index]; + pci_unmap_single(priv->pci_dev, + pci_unmap_addr(meta, mapping), + pci_unmap_len(meta, len), + PCI_DMA_BIDIRECTIONAL); + /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { meta->source->reply_page = (unsigned long)rxb_addr(rxb); -- cgit v1.2.3 From 89f186a8b64a4c90a219cfd94c26de5cfea54b84 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:11 -0700 Subject: iwlwifi: move iwl_[un]init_drv to iwlagn Since iwlagn is the only user of these functions, move it to this module. This results in a bit more code moving than just these functions since the functions only used by them are also moved and we need to export the symbols previously available to them directly. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 90 +++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-calib.c | 1 + drivers/net/wireless/iwlwifi/iwl-core.c | 93 -------------------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 - drivers/net/wireless/iwlwifi/iwl-scan.c | 1 + 5 files changed, 92 insertions(+), 95 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0cb95bfd15a5..2814565fa3b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2972,6 +2972,96 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) del_timer_sync(&priv->statistics_periodic); } +static void iwl_init_hw_rates(struct iwl_priv *priv, + struct ieee80211_rate *rates) +{ + int 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_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) { + /* + * If CCK != 1M then set short preamble rate flag. + */ + rates[i].flags |= + (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ? + 0 : IEEE80211_RATE_SHORT_PREAMBLE; + } + } +} + +static int iwl_init_drv(struct iwl_priv *priv) +{ + int ret; + + priv->ibss_beacon = NULL; + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->sta_lock); + spin_lock_init(&priv->hcmd_lock); + + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); + + /* Clear the driver's (not device's) station table */ + iwl_clear_stations_table(priv); + + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->band = IEEE80211_BAND_2GHZ; + + priv->iw_mode = NL80211_IFTYPE_STATION; + + /* Choose which receivers/antennas to use */ + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + + iwl_init_scan_params(priv); + + iwl_reset_qos(priv); + + priv->qos_data.qos_active = 0; + priv->qos_data.qos_cap.val = 0; + + priv->rates_mask = IWL_RATES_MASK; + /* 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) { + IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); + goto err; + } + + ret = iwlcore_init_geos(priv); + if (ret) { + IWL_ERR(priv, "initializing geos failed: %d\n", ret); + goto err_free_channel_map; + } + iwl_init_hw_rates(priv, priv->ieee_rates); + + return 0; + +err_free_channel_map: + iwl_free_channel_map(priv); +err: + return ret; +} + +static void iwl_uninit_drv(struct iwl_priv *priv) +{ + iwl_calib_free_results(priv); + iwlcore_free_geos(priv); + iwl_free_channel_map(priv); + kfree(priv->scan); +} + static struct attribute *iwl_sysfs_entries[] = { &dev_attr_flags.attr, &dev_attr_filter_flags.attr, diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 1f801eb9fbff..d994de7438d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -132,6 +132,7 @@ void iwl_calib_free_results(struct iwl_priv *priv) priv->calib_results[i].buf_len = 0; } } +EXPORT_SYMBOL(iwl_calib_free_results); /***************************************************************************** * RUNTIME calibrations framework diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index addc9ad5a5c6..256c9a49fa3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -451,28 +451,6 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, } } -static void iwlcore_init_hw_rates(struct iwl_priv *priv, - struct ieee80211_rate *rates) -{ - int 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_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) { - /* - * If CCK != 1M then set short preamble rate flag. - */ - rates[i].flags |= - (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ? - 0 : IEEE80211_RATE_SHORT_PREAMBLE; - } - } -} - - /** * iwlcore_init_geos - Initialize mac80211's geo/channel info based from eeprom */ @@ -1571,68 +1549,6 @@ int iwl_set_hw_params(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_set_hw_params); -int iwl_init_drv(struct iwl_priv *priv) -{ - int ret; - - priv->ibss_beacon = NULL; - - spin_lock_init(&priv->lock); - spin_lock_init(&priv->sta_lock); - spin_lock_init(&priv->hcmd_lock); - - INIT_LIST_HEAD(&priv->free_frames); - - mutex_init(&priv->mutex); - - /* Clear the driver's (not device's) station table */ - iwl_clear_stations_table(priv); - - priv->ieee_channels = NULL; - priv->ieee_rates = NULL; - priv->band = IEEE80211_BAND_2GHZ; - - priv->iw_mode = NL80211_IFTYPE_STATION; - - /* Choose which receivers/antennas to use */ - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv); - - iwl_init_scan_params(priv); - - iwl_reset_qos(priv); - - priv->qos_data.qos_active = 0; - priv->qos_data.qos_cap.val = 0; - - priv->rates_mask = IWL_RATES_MASK; - /* 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) { - IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); - goto err; - } - - ret = iwlcore_init_geos(priv); - if (ret) { - IWL_ERR(priv, "initializing geos failed: %d\n", ret); - goto err_free_channel_map; - } - iwlcore_init_hw_rates(priv, priv->ieee_rates); - - return 0; - -err_free_channel_map: - iwl_free_channel_map(priv); -err: - return ret; -} -EXPORT_SYMBOL(iwl_init_drv); - int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret = 0; @@ -1680,15 +1596,6 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) } EXPORT_SYMBOL(iwl_set_tx_power); -void iwl_uninit_drv(struct iwl_priv *priv) -{ - iwl_calib_free_results(priv); - iwlcore_free_geos(priv); - iwl_free_channel_map(priv); - kfree(priv->scan); -} -EXPORT_SYMBOL(iwl_uninit_drv); - #define ICT_COUNT (PAGE_SIZE/sizeof(u32)) /* Free dram table */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b875dcfca2d6..ddf0998fb752 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -316,8 +316,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast); int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); -int iwl_init_drv(struct iwl_priv *priv); -void iwl_uninit_drv(struct iwl_priv *priv); bool iwl_is_monitor_mode(struct iwl_priv *priv); void iwl_post_associate(struct iwl_priv *priv); void iwl_bss_info_changed(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 4fca65a2fe9c..1eb0d0bf1fe4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -401,6 +401,7 @@ void iwl_init_scan_params(struct iwl_priv *priv) if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; } +EXPORT_SYMBOL(iwl_init_scan_params); static int iwl_scan_initiate(struct iwl_priv *priv) { -- cgit v1.2.3 From 9a9ca65fbfa1cd14a6c016b793d61492f9f613d0 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:12 -0700 Subject: iwlwifi: split adding broadcast station from others In preparation for some station management changes we split the addition of a broadcast station from the other stations. Later we will rely on mac80211 to direct all management (addition/removal) of all stations except the broadcast station. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++--- drivers/net/wireless/iwlwifi/iwl-sta.c | 62 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-sta.h | 1 + 3 files changed, 65 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2814565fa3b4..4a13f7e21d63 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -190,11 +190,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) priv->start_calib = 0; /* Add the broadcast address so we can send broadcast frames */ - if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == - IWL_INVALID_STATION) { - IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); - return -EIO; - } + iwl_add_bcast_station(priv); /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ @@ -2524,7 +2520,7 @@ void iwl_config_ap(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); iwl_activate_qos(priv, 1); spin_unlock_irqrestore(&priv->lock, flags); - iwl_rxon_add_station(priv, iwl_bcast_addr, 0); + iwl_add_bcast_station(priv); } iwl_send_beacon_cmd(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index dc74c16d36a8..ce1ceac19c7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1029,6 +1029,68 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) } EXPORT_SYMBOL(iwl_rxon_add_station); +/** + * iwl_sta_init_bcast_lq - Initialize a bcast station's hardware rate table + * + * NOTE: Run REPLY_ADD_STA command to set up station table entry, before + * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, + * which requires station table entry to exist). + */ +static void iwl_sta_init_bcast_lq(struct iwl_priv *priv) +{ + int i, r; + struct iwl_link_quality_cmd link_cmd = { + .reserved1 = 0, + }; + u32 rate_flags; + + /* Set up the rate scaling to start at selected rate, fall back + * all the way down to 1M in IEEE order, and then spin on 1M */ + if (priv->band == IEEE80211_BAND_5GHZ) + r = IWL_RATE_6M_INDEX; + else + r = IWL_RATE_1M_INDEX; + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + rate_flags = 0; + if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) + rate_flags |= RATE_MCS_CCK_MSK; + + rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << + RATE_MCS_ANT_POS; + + link_cmd.rs_table[i].rate_n_flags = + iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); + r = iwl_get_prev_ieee_rate(r); + } + + link_cmd.general_params.single_stream_ant_msk = + first_antenna(priv->hw_params.valid_tx_ant); + link_cmd.general_params.dual_stream_ant_msk = 3; + link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + link_cmd.agg_params.agg_time_limit = + cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); + + /* Update the rate scaling for control frame Tx to AP */ + link_cmd.sta_id = priv->hw_params.bcast_sta_id; + + iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, + sizeof(link_cmd), &link_cmd, NULL); +} + + +/** + * iwl_add_bcast_station - add broadcast station into station table. + */ +void iwl_add_bcast_station(struct iwl_priv *priv) +{ + iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL); + + /* Set up default rate scaling table in device's station table */ + iwl_sta_init_bcast_lq(priv); +} +EXPORT_SYMBOL(iwl_add_bcast_station); + /** * iwl_get_sta_id - Find station's index within station table * diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 6deebade6361..1c382de80d49 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -52,6 +52,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv, const u8 *addr, u32 iv32, u16 *phase1key); int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); +void iwl_add_bcast_station(struct iwl_priv *priv); int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); void iwl_clear_stations_table(struct iwl_priv *priv); int iwl_get_free_ucode_key_index(struct iwl_priv *priv); -- cgit v1.2.3 From 62a94926183374d8414ab2ec633d9fe9530644ec Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:13 -0700 Subject: iwl3945: store station rate scale information in mac80211 station structure Currently the rate scale information is pointed to from the mac80211 station structure but since that is the only member we might as well make it part of the structure. Also move the rate scaling initialization to the init function, no need to do it when we allocate the structure. This fits with how mac80211 deals with rate scaling information (it always calls init after allocation) and makes it easier for us to later call initialization directly. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 99 ++++++++---------------------- drivers/net/wireless/iwlwifi/iwl-3945.h | 35 ++++++++++- 2 files changed, 60 insertions(+), 74 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index cbb0585083a9..819a81bbb1b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -42,38 +42,6 @@ #define RS_NAME "iwl-3945-rs" -struct iwl3945_rate_scale_data { - u64 data; - s32 success_counter; - s32 success_ratio; - s32 counter; - s32 average_tpt; - unsigned long stamp; -}; - -struct iwl3945_rs_sta { - spinlock_t lock; - struct iwl_priv *priv; - s32 *expected_tpt; - unsigned long last_partial_flush; - unsigned long last_flush; - u32 flush_time; - u32 last_tx_packets; - u32 tx_packets; - u8 tgg; - u8 flush_pending; - u8 start_rate; - u8 ibss_sta_added; - struct timer_list rate_scale_flush; - struct iwl3945_rate_scale_data win[IWL_RATE_COUNT_3945]; -#ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *rs_sta_dbgfs_stats_table_file; -#endif - - /* used to be in sta_info */ - int last_txrate_idx; -}; - static s32 iwl3945_expected_tpt_g[IWL_RATE_COUNT_3945] = { 7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202 }; @@ -370,6 +338,28 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, IWL_DEBUG_RATE(priv, "enter\n"); + spin_lock_init(&rs_sta->lock); + + rs_sta->priv = priv; + + rs_sta->start_rate = IWL_RATE_INVALID; + + /* default to just 802.11b */ + rs_sta->expected_tpt = iwl3945_expected_tpt_b; + + rs_sta->last_partial_flush = jiffies; + rs_sta->last_flush = jiffies; + rs_sta->flush_time = IWL_RATE_FLUSH; + rs_sta->last_tx_packets = 0; + rs_sta->ibss_sta_added = 0; + + init_timer(&rs_sta->rate_scale_flush); + rs_sta->rate_scale_flush.data = (unsigned long)rs_sta; + rs_sta->rate_scale_flush.function = &iwl3945_bg_rate_scale_flush; + + for (i = 0; i < IWL_RATE_COUNT_3945; i++) + iwl3945_clear_window(&rs_sta->win[i]); + /* TODO: what is a good starting rate for STA? About middle? Maybe not * the lowest or the highest rate.. Could consider using RSSI from * previous packets? Need to have IEEE 802.1X auth succeed immediately @@ -409,45 +399,11 @@ static void *rs_alloc_sta(void *iwl_priv, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl3945_rs_sta *rs_sta; struct iwl3945_sta_priv *psta = (void *) sta->drv_priv; - struct iwl_priv *priv = iwl_priv; - int i; - - /* - * XXX: If it's using sta->drv_priv anyway, it might - * as well just put all the information there. - */ + struct iwl_priv *priv __maybe_unused = iwl_priv; IWL_DEBUG_RATE(priv, "enter\n"); - rs_sta = kzalloc(sizeof(struct iwl3945_rs_sta), gfp); - if (!rs_sta) { - IWL_DEBUG_RATE(priv, "leave: ENOMEM\n"); - return NULL; - } - - psta->rs_sta = rs_sta; - - spin_lock_init(&rs_sta->lock); - - rs_sta->priv = priv; - - rs_sta->start_rate = IWL_RATE_INVALID; - - /* default to just 802.11b */ - rs_sta->expected_tpt = iwl3945_expected_tpt_b; - - rs_sta->last_partial_flush = jiffies; - rs_sta->last_flush = jiffies; - rs_sta->flush_time = IWL_RATE_FLUSH; - rs_sta->last_tx_packets = 0; - rs_sta->ibss_sta_added = 0; - - init_timer(&rs_sta->rate_scale_flush); - rs_sta->rate_scale_flush.data = (unsigned long)rs_sta; - rs_sta->rate_scale_flush.function = &iwl3945_bg_rate_scale_flush; - - for (i = 0; i < IWL_RATE_COUNT_3945; i++) - iwl3945_clear_window(&rs_sta->win[i]); + rs_sta = &psta->rs_sta; IWL_DEBUG_RATE(priv, "leave\n"); @@ -458,14 +414,11 @@ static void rs_free_sta(void *iwl_priv, struct ieee80211_sta *sta, void *priv_sta) { struct iwl3945_sta_priv *psta = (void *) sta->drv_priv; - struct iwl3945_rs_sta *rs_sta = priv_sta; + struct iwl3945_rs_sta *rs_sta = &psta->rs_sta; struct iwl_priv *priv __maybe_unused = rs_sta->priv; - psta->rs_sta = NULL; - IWL_DEBUG_RATE(priv, "enter\n"); del_timer_sync(&rs_sta->rate_scale_flush); - kfree(rs_sta); IWL_DEBUG_RATE(priv, "leave\n"); } @@ -967,7 +920,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) } psta = (void *) sta->drv_priv; - rs_sta = psta->rs_sta; + rs_sta = &psta->rs_sta; spin_lock_irqsave(&rs_sta->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index ebb999a51b58..2b0d65c5780a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -74,8 +74,41 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; /* Module parameters accessible from iwl-*.c */ extern struct iwl_mod_params iwl3945_mod_params; +struct iwl3945_rate_scale_data { + u64 data; + s32 success_counter; + s32 success_ratio; + s32 counter; + s32 average_tpt; + unsigned long stamp; +}; + +struct iwl3945_rs_sta { + spinlock_t lock; + struct iwl_priv *priv; + s32 *expected_tpt; + unsigned long last_partial_flush; + unsigned long last_flush; + u32 flush_time; + u32 last_tx_packets; + u32 tx_packets; + u8 tgg; + u8 flush_pending; + u8 start_rate; + u8 ibss_sta_added; + struct timer_list rate_scale_flush; + struct iwl3945_rate_scale_data win[IWL_RATE_COUNT_3945]; +#ifdef CONFIG_MAC80211_DEBUGFS + struct dentry *rs_sta_dbgfs_stats_table_file; +#endif + + /* used to be in sta_info */ + int last_txrate_idx; +}; + + struct iwl3945_sta_priv { - struct iwl3945_rs_sta *rs_sta; + struct iwl3945_rs_sta rs_sta; }; enum iwl3945_antenna { -- cgit v1.2.3 From 5ad13f8ce76814b37842c15301287efd607c6d26 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:14 -0700 Subject: iwlagn: move rate scale initialization to init function This fits better in how the callbacks operate (alloc does allocation and init does initialization). This also helps if we later want to do our own initialization without relying on the mac80211 allocation. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 27d4ece4d467..43edd8fd4405 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2477,19 +2477,12 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta; struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; struct iwl_priv *priv; - int i, j; priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE(priv, "create station rate scale window\n"); lq_sta = &sta_priv->lq_sta; - lq_sta->lq.sta_id = 0xff; - - for (j = 0; j < LQ_SIZE; j++) - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); - return lq_sta; } @@ -2502,6 +2495,12 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct iwl_lq_sta *lq_sta = priv_sta; + lq_sta->lq.sta_id = 0xff; + + for (j = 0; j < LQ_SIZE; j++) + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); + lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->supp_rates[sband->band]; for (j = 0; j < LQ_SIZE; j++) -- cgit v1.2.3 From f2f21b4928489e1cf6c289d2f429e75c6dee61b5 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:15 -0700 Subject: iwlwifi: print warning when sending host command fails More information than the "-EIO" return code will be useful here. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index b46967ff3806..05e75109d842 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -979,7 +979,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) !(cmd->flags & CMD_SIZE_HUGE)); if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { - IWL_DEBUG_INFO(priv, "Not sending command - RF/CT KILL\n"); + IWL_WARN(priv, "Not sending command - %s KILL\n", + iwl_is_rfkill(priv) ? "RF" : "CT"); return -EIO; } -- cgit v1.2.3 From fe1bcbfda77bf6fa3bbad8bf26b9e9ab23fbe345 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 30 Oct 2009 14:36:16 -0700 Subject: iwlwifi: coex API data structure Add data structure define for COEX_MEDIUM_NOTIFICATION and COEX_EVENT_CMD host commands. COEX_MEDIUM_NOTIFICATION is notification from uCode to host to indicate medium changes. COEX_EVENT_CMD is from host to uCode for coex event request. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 69 +++++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 + 2 files changed, 68 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 954bad60355d..43dd6af00892 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3503,30 +3503,42 @@ struct iwl_led_cmd { } __attribute__ ((packed)); /* - * Coexistence WIFI/WIMAX Command - * COEX_PRIORITY_TABLE_CMD = 0x5a - * + * station priority table entries + * also used as potential "events" value for both + * COEX_MEDIUM_NOTIFICATION and COEX_EVENT_CMD */ enum { + /* un-association part */ COEX_UNASSOC_IDLE = 0, COEX_UNASSOC_MANUAL_SCAN = 1, COEX_UNASSOC_AUTO_SCAN = 2, + /* calibration */ COEX_CALIBRATION = 3, COEX_PERIODIC_CALIBRATION = 4, + /* connection */ COEX_CONNECTION_ESTAB = 5, + /* association part */ COEX_ASSOCIATED_IDLE = 6, COEX_ASSOC_MANUAL_SCAN = 7, COEX_ASSOC_AUTO_SCAN = 8, COEX_ASSOC_ACTIVE_LEVEL = 9, + /* RF ON/OFF */ COEX_RF_ON = 10, COEX_RF_OFF = 11, COEX_STAND_ALONE_DEBUG = 12, + /* IPAN */ COEX_IPAN_ASSOC_LEVEL = 13, + /* reserved */ COEX_RSRVD1 = 14, COEX_RSRVD2 = 15, COEX_NUM_OF_EVENTS = 16 }; +/* + * Coexistence WIFI/WIMAX Command + * COEX_PRIORITY_TABLE_CMD = 0x5a + * + */ struct iwl_wimax_coex_event_entry { u8 request_prio; u8 win_medium_prio; @@ -3551,6 +3563,55 @@ struct iwl_wimax_coex_cmd { struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS]; } __attribute__ ((packed)); +/* + * Coexistence MEDIUM NOTIFICATION + * COEX_MEDIUM_NOTIFICATION = 0x5b + * + * notification from uCode to host to indicate medium changes + * + */ +/* + * status field + * bit 0 - 2: medium status + * bit 3: medium change indication + * bit 4 - 31: reserved + */ +/* status option values, (0 - 2 bits) */ +#define COEX_MEDIUM_BUSY (0x0) /* radio belongs to WiMAX */ +#define COEX_MEDIUM_ACTIVE (0x1) /* radio belongs to WiFi */ +#define COEX_MEDIUM_PRE_RELEASE (0x2) /* received radio release */ +#define COEX_MEDIUM_MSK (0x7) + +/* send notification status (1 bit) */ +#define COEX_MEDIUM_CHANGED (0x8) +#define COEX_MEDIUM_CHANGED_MSK (0x8) +#define COEX_MEDIUM_SHIFT (3) + +struct iwl_coex_medium_notification { + __le32 status; + __le32 events; +} __attribute__ ((packed)); + +/* + * Coexistence EVENT Command + * COEX_EVENT_CMD = 0x5c + * + * send from host to uCode for coex event request. + */ +/* flags options */ +#define COEX_EVENT_REQUEST_MSK (0x1) + +struct iwl_coex_event_cmd { + u8 flags; + u8 event; + __le16 reserved; +} __attribute__ ((packed)); + +struct iwl_coex_event_resp { + __le32 status; +} __attribute__ ((packed)); + + /****************************************************************************** * (13) * Union of all expected notifications/responses: @@ -3587,6 +3648,8 @@ struct iwl_rx_packet { struct iwl_notif_statistics stats; struct iwl_compressed_ba_resp compressed_ba; struct iwl_missed_beacon_notif missed_beacon; + struct iwl_coex_medium_notification coex_medium_notif; + struct iwl_coex_event_resp coex_event; __le32 status; u8 raw[0]; } u; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index f2a60dc4109f..905645d15a9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -55,6 +55,8 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_LEDS_CMD); IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); IWL_CMD(COEX_PRIORITY_TABLE_CMD); + IWL_CMD(COEX_MEDIUM_NOTIFICATION); + IWL_CMD(COEX_EVENT_CMD); IWL_CMD(RADAR_NOTIFICATION); IWL_CMD(REPLY_QUIET_CMD); IWL_CMD(REPLY_CHANNEL_SWITCH); -- cgit v1.2.3 From 3f3e0376bb14ac7bfd8ac3e9824b2ad04d945e18 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 30 Oct 2009 14:36:17 -0700 Subject: iwlwifi: add SM PS support for 6x50 series Spatial Multiplexing Power Save was disabled to achieve better throughput while in power save mode by activating all the rx chains all the time. By doing so, the device power consumption is high. Enable static/dynamic spatial multiplexing power save if device support it, which can lower the power consumption without impact throughput. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-agn.c | 4 +++ drivers/net/wireless/iwlwifi/iwl-core.c | 48 ++++++++++++++++++++++++++------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl-sta.c | 5 ++++ 6 files changed, 52 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 2f841a8576e0..a4a8b5e2f411 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -490,6 +490,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .support_sm_ps = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -579,6 +580,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .support_sm_ps = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4a13f7e21d63..b5fe8f87aa7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3011,6 +3011,10 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->band = IEEE80211_BAND_2GHZ; priv->iw_mode = NL80211_IFTYPE_STATION; + if (priv->cfg->support_sm_ps) + priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DYNAMIC; + else + priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 256c9a49fa3b..c4ff381e440e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -414,8 +414,12 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, 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)); + if (priv->cfg->support_sm_ps) + ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & + (WLAN_HT_CAP_SM_PS_DYNAMIC << 2)); + else + 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.ht40_channel & BIT(band)) { @@ -963,17 +967,35 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) } /* - * When we are in power saving, there's no difference between - * using multiple chains or just a single chain, but due to the - * lack of SM PS we lose a lot of throughput if we use just a - * single chain. - * - * Therefore, use the active count here (which will use multiple - * chains unless connected to a legacy AP). + * When we are in power saving mode, unless device support spatial + * multiplexing power save, use the active count for rx chain count. */ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) { - return active_cnt; + int idle_cnt = active_cnt; + bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); + + if (priv->cfg->support_sm_ps) { + /* # Rx chains when idling and maybe trying to save power */ + switch (priv->current_ht_config.sm_ps) { + case WLAN_HT_CAP_SM_PS_STATIC: + case WLAN_HT_CAP_SM_PS_DYNAMIC: + idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : + IWL_NUM_IDLE_CHAINS_SINGLE; + break; + case WLAN_HT_CAP_SM_PS_DISABLED: + idle_cnt = (is_cam) ? active_cnt : + IWL_NUM_IDLE_CHAINS_SINGLE; + break; + case WLAN_HT_CAP_SM_PS_INVALID: + default: + IWL_ERR(priv, "invalid sm_ps mode %d\n", + priv->current_ht_config.sm_ps); + WARN_ON(1); + break; + } + } + return idle_cnt; } /* up to 4 chains */ @@ -2257,6 +2279,12 @@ static void iwl_ht_conf(struct iwl_priv *priv, >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; maxstreams += 1; + ht_conf->sm_ps = + (u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS) + >> 2); + IWL_DEBUG_MAC80211(priv, "sm_ps: 0x%x\n", + ht_conf->sm_ps); + if ((ht_cap->mcs.rx_mask[1] == 0) && (ht_cap->mcs.rx_mask[2] == 0)) ht_conf->single_chain_sufficient = true; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ddf0998fb752..d2e47dab38d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -228,6 +228,7 @@ struct iwl_mod_params { * @chain_noise_num_beacons: number of beacons used to compute chain noise * @adv_thermal_throttle: support advance thermal throttle * @support_ct_kill_exit: support ct kill exit condition + * @support_sm_ps: support spatial multiplexing power save * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -283,6 +284,7 @@ struct iwl_cfg { const bool supports_idle; bool adv_thermal_throttle; bool support_ct_kill_exit; + bool support_sm_ps; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e7ce67387662..cb2642c18da4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -517,6 +517,7 @@ struct iwl_ht_config { bool is_ht; bool is_40mhz; bool single_chain_sufficient; + u8 sm_ps; /* BSS related data */ u8 extension_chan_offset; u8 ht_protection; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index ce1ceac19c7d..74cc8dbe9359 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -182,6 +182,11 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, goto done; mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; + IWL_DEBUG_ASSOC(priv, "spatial multiplexing power save mode: %s\n", + (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? + "static" : + (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? + "dynamic" : "disabled"); sta_flags = priv->stations[index].sta.station_flags; -- cgit v1.2.3 From 1933ac4d9377ed44caba45abe1531ec1bc14bb63 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 30 Oct 2009 14:36:18 -0700 Subject: iwlwifi: add wimax/wifi coexist support for 6x50 series For 6x50 series, it is wimax/wifi combo device, so driver need to enable the wimax/wifi co-exist function and send the coexist event priority table to uCode for operation. The priority table will be used by uCode to determine what is the proper action it should take when co-exist with WiMAX. For example, when WiFi runs a scan, it must own radio exclusively, therefore will disconnect WiMAX if WiMAX is connected. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 12 +--- drivers/net/wireless/iwlwifi/iwl-6000.c | 3 + drivers/net/wireless/iwlwifi/iwl-commands.h | 92 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 59 ++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 3 + 5 files changed, 158 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d256fecc6cda..910217f0ad8a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -591,16 +591,6 @@ static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); } -static int iwl5000_send_wimax_coex(struct iwl_priv *priv) -{ - struct iwl_wimax_coex_cmd coex_cmd; - - memset(&coex_cmd, 0, sizeof(coex_cmd)); - - return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD, - sizeof(coex_cmd), &coex_cmd); -} - int iwl5000_alive_notify(struct iwl_priv *priv) { u32 a; @@ -681,7 +671,7 @@ int iwl5000_alive_notify(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); - iwl5000_send_wimax_coex(priv); + iwl_send_wimax_coex(priv); iwl5000_set_Xtal_calib(priv); iwl_send_calib_results(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a4a8b5e2f411..70e117f8d0c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -491,6 +491,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .adv_thermal_throttle = true, .support_ct_kill_exit = true, .support_sm_ps = true, + .support_wimax_coexist = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -520,6 +521,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .support_wimax_coexist = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -581,6 +583,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .adv_thermal_throttle = true, .support_ct_kill_exit = true, .support_sm_ps = true, + .support_wimax_coexist = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 43dd6af00892..b62c90ec9e1e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3507,6 +3507,98 @@ struct iwl_led_cmd { * also used as potential "events" value for both * COEX_MEDIUM_NOTIFICATION and COEX_EVENT_CMD */ + +/* + * COEX events entry flag masks + * RP - Requested Priority + * WP - Win Medium Priority: priority assigned when the contention has been won + */ +#define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG (0x1) +#define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG (0x2) +#define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG (0x4) + +#define COEX_CU_UNASSOC_IDLE_RP 4 +#define COEX_CU_UNASSOC_MANUAL_SCAN_RP 4 +#define COEX_CU_UNASSOC_AUTO_SCAN_RP 4 +#define COEX_CU_CALIBRATION_RP 4 +#define COEX_CU_PERIODIC_CALIBRATION_RP 4 +#define COEX_CU_CONNECTION_ESTAB_RP 4 +#define COEX_CU_ASSOCIATED_IDLE_RP 4 +#define COEX_CU_ASSOC_MANUAL_SCAN_RP 4 +#define COEX_CU_ASSOC_AUTO_SCAN_RP 4 +#define COEX_CU_ASSOC_ACTIVE_LEVEL_RP 4 +#define COEX_CU_RF_ON_RP 6 +#define COEX_CU_RF_OFF_RP 4 +#define COEX_CU_STAND_ALONE_DEBUG_RP 6 +#define COEX_CU_IPAN_ASSOC_LEVEL_RP 4 +#define COEX_CU_RSRVD1_RP 4 +#define COEX_CU_RSRVD2_RP 4 + +#define COEX_CU_UNASSOC_IDLE_WP 3 +#define COEX_CU_UNASSOC_MANUAL_SCAN_WP 3 +#define COEX_CU_UNASSOC_AUTO_SCAN_WP 3 +#define COEX_CU_CALIBRATION_WP 3 +#define COEX_CU_PERIODIC_CALIBRATION_WP 3 +#define COEX_CU_CONNECTION_ESTAB_WP 3 +#define COEX_CU_ASSOCIATED_IDLE_WP 3 +#define COEX_CU_ASSOC_MANUAL_SCAN_WP 3 +#define COEX_CU_ASSOC_AUTO_SCAN_WP 3 +#define COEX_CU_ASSOC_ACTIVE_LEVEL_WP 3 +#define COEX_CU_RF_ON_WP 3 +#define COEX_CU_RF_OFF_WP 3 +#define COEX_CU_STAND_ALONE_DEBUG_WP 6 +#define COEX_CU_IPAN_ASSOC_LEVEL_WP 3 +#define COEX_CU_RSRVD1_WP 3 +#define COEX_CU_RSRVD2_WP 3 + +#define COEX_UNASSOC_IDLE_FLAGS 0 +#define COEX_UNASSOC_MANUAL_SCAN_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_UNASSOC_AUTO_SCAN_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_CALIBRATION_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_PERIODIC_CALIBRATION_FLAGS 0 +/* + * COEX_CONNECTION_ESTAB: + * we need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network. + */ +#define COEX_CONNECTION_ESTAB_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG) +#define COEX_ASSOCIATED_IDLE_FLAGS 0 +#define COEX_ASSOC_MANUAL_SCAN_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_ASSOC_AUTO_SCAN_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_ASSOC_ACTIVE_LEVEL_FLAGS 0 +#define COEX_RF_ON_FLAGS 0 +#define COEX_RF_OFF_FLAGS 0 +#define COEX_STAND_ALONE_DEBUG_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_IPAN_ASSOC_LEVEL_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG) +#define COEX_RSRVD1_FLAGS 0 +#define COEX_RSRVD2_FLAGS 0 +/* + * COEX_CU_RF_ON is the event wrapping all radio ownership. + * We need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network. + */ +#define COEX_CU_RF_ON_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG) + + enum { /* un-association part */ COEX_UNASSOC_IDLE = 0, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c4ff381e440e..7373b2f50aca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -46,6 +46,37 @@ MODULE_VERSION(IWLWIFI_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); +static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { + {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP, + 0, COEX_UNASSOC_IDLE_FLAGS}, + {COEX_CU_UNASSOC_MANUAL_SCAN_RP, COEX_CU_UNASSOC_MANUAL_SCAN_WP, + 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, + {COEX_CU_UNASSOC_AUTO_SCAN_RP, COEX_CU_UNASSOC_AUTO_SCAN_WP, + 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, + {COEX_CU_CALIBRATION_RP, COEX_CU_CALIBRATION_WP, + 0, COEX_CALIBRATION_FLAGS}, + {COEX_CU_PERIODIC_CALIBRATION_RP, COEX_CU_PERIODIC_CALIBRATION_WP, + 0, COEX_PERIODIC_CALIBRATION_FLAGS}, + {COEX_CU_CONNECTION_ESTAB_RP, COEX_CU_CONNECTION_ESTAB_WP, + 0, COEX_CONNECTION_ESTAB_FLAGS}, + {COEX_CU_ASSOCIATED_IDLE_RP, COEX_CU_ASSOCIATED_IDLE_WP, + 0, COEX_ASSOCIATED_IDLE_FLAGS}, + {COEX_CU_ASSOC_MANUAL_SCAN_RP, COEX_CU_ASSOC_MANUAL_SCAN_WP, + 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, + {COEX_CU_ASSOC_AUTO_SCAN_RP, COEX_CU_ASSOC_AUTO_SCAN_WP, + 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, + {COEX_CU_ASSOC_ACTIVE_LEVEL_RP, COEX_CU_ASSOC_ACTIVE_LEVEL_WP, + 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, + {COEX_CU_RF_ON_RP, COEX_CU_RF_ON_WP, 0, COEX_CU_RF_ON_FLAGS}, + {COEX_CU_RF_OFF_RP, COEX_CU_RF_OFF_WP, 0, COEX_RF_OFF_FLAGS}, + {COEX_CU_STAND_ALONE_DEBUG_RP, COEX_CU_STAND_ALONE_DEBUG_WP, + 0, COEX_STAND_ALONE_DEBUG_FLAGS}, + {COEX_CU_IPAN_ASSOC_LEVEL_RP, COEX_CU_IPAN_ASSOC_LEVEL_WP, + 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, + {COEX_CU_RSRVD1_RP, COEX_CU_RSRVD1_WP, 0, COEX_RSRVD1_FLAGS}, + {COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS} +}; + #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ IWL_RATE_SISO_##s##M_PLCP, \ @@ -2865,6 +2896,34 @@ void iwl_free_txq_mem(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_free_txq_mem); +int iwl_send_wimax_coex(struct iwl_priv *priv) +{ + struct iwl_wimax_coex_cmd uninitialized_var(coex_cmd); + + if (priv->cfg->support_wimax_coexist) { + /* UnMask wake up src at associated sleep */ + coex_cmd.flags |= COEX_FLAGS_ASSOC_WA_UNMASK_MSK; + + /* UnMask wake up src at unassociated sleep */ + coex_cmd.flags |= COEX_FLAGS_UNASSOC_WA_UNMASK_MSK; + memcpy(coex_cmd.sta_prio, cu_priorities, + sizeof(struct iwl_wimax_coex_event_entry) * + COEX_NUM_OF_EVENTS); + + /* enabling the coexistence feature */ + coex_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK; + + /* enabling the priorities tables */ + coex_cmd.flags |= COEX_FLAGS_STA_TABLE_VALID_MSK; + } else { + /* coexistence is disabled */ + memset(&coex_cmd, 0, sizeof(coex_cmd)); + } + return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD, + sizeof(coex_cmd), &coex_cmd); +} +EXPORT_SYMBOL(iwl_send_wimax_coex); + #ifdef CONFIG_IWLWIFI_DEBUGFS #define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index d2e47dab38d4..9574d8f33537 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -229,6 +229,7 @@ struct iwl_mod_params { * @adv_thermal_throttle: support advance thermal throttle * @support_ct_kill_exit: support ct kill exit condition * @support_sm_ps: support spatial multiplexing power save + * @support_wimax_coexist: support wimax/wifi co-exist * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -285,6 +286,7 @@ struct iwl_cfg { bool adv_thermal_throttle; bool support_ct_kill_exit; bool support_sm_ps; + const bool support_wimax_coexist; }; /*************************** @@ -340,6 +342,7 @@ int iwl_alloc_txq_mem(struct iwl_priv *priv); void iwl_free_txq_mem(struct iwl_priv *priv); void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags); +int iwl_send_wimax_coex(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_alloc_traffic_mem(struct iwl_priv *priv); void iwl_free_traffic_mem(struct iwl_priv *priv); -- cgit v1.2.3 From 5ed176e1c425f9bd1af161d66d348f6116a04fc6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Nov 2009 14:42:28 +0100 Subject: mac80211: make ieee80211_find_sta per virtual interface Since we have a TODO item to make all station management dependent on virtual interfaces, I figured I'd start with pushing such a change to drivers before more drivers start using the ieee80211_find_sta() API with a hw pointer and cause us grief later on. For now continue exporting the old API in form of ieee80211_find_sta_by_hw(), but discourage its use strongly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 3 ++- drivers/net/wireless/ath/ath9k/xmit.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- include/net/mac80211.h | 25 +++++++++++++++++++++++-- net/mac80211/sta_info.c | 18 ++++++++++++++++-- 7 files changed, 47 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c880a55939bf..355dd1834e1d 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -202,7 +202,8 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, } rcu_read_lock(); - sta = ieee80211_find_sta(sc->hw, hdr->addr2); + /* XXX: use ieee80211_find_sta! */ + sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr2); if (sta) { an = (struct ath_node *) sta->drv_priv; if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD && diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2a4efcbced60..8e052f406c35 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -282,7 +282,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, rcu_read_lock(); - sta = ieee80211_find_sta(sc->hw, hdr->addr1); + /* XXX: use ieee80211_find_sta! */ + sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr1); if (!sta) { rcu_read_unlock(); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 819a81bbb1b7..dc81e19674f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -913,7 +913,8 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) rcu_read_lock(); - sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr); + sta = ieee80211_find_sta(priv->vif, + priv->stations[sta_id].sta.sta.addr); if (!sta) { rcu_read_unlock(); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7373b2f50aca..e0b5b4aef41d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2300,7 +2300,7 @@ static void iwl_ht_conf(struct iwl_priv *priv, switch (priv->iw_mode) { case NL80211_IFTYPE_STATION: rcu_read_lock(); - sta = ieee80211_find_sta(priv->hw, priv->bssid); + sta = ieee80211_find_sta(priv->vif, priv->bssid); if (sta) { struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; int maxstreams; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 74cc8dbe9359..eba36f737388 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1017,7 +1017,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) */ if (priv->current_ht_config.is_ht) { rcu_read_lock(); - sta = ieee80211_find_sta(priv->hw, addr); + sta = ieee80211_find_sta(priv->vif, addr); if (sta) { memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); cur_ht_config = &ht_config; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e12293e60ac1..7f035d779db9 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2106,15 +2106,36 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, /** * ieee80211_find_sta - find a station * - * @hw: pointer as obtained from ieee80211_alloc_hw() + * @vif: virtual interface to look for station on * @addr: station's address * * This function must be called under RCU lock and the * resulting pointer is only valid under RCU lock as well. */ -struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, +struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, const u8 *addr); +/** + * ieee80211_find_sta_by_hw - find a station on hardware + * + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @addr: station's address + * + * This function must be called under RCU lock and the + * resulting pointer is only valid under RCU lock as well. + * + * NOTE: This function should not be used! When mac80211 is converted + * internally to properly keep track of stations on multiple + * virtual interfaces, it will not always know which station to + * return here since a single address might be used by multiple + * logical stations (e.g. consider a station connecting to another + * BSSID on the same AP hardware without disconnecting first). + * + * DO NOT USE THIS FUNCTION. + */ +struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, + const u8 *addr); + /** * ieee80211_beacon_loss - inform hardware does not receive beacons * diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 594f2318c3d8..cde2da7a74df 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -801,8 +801,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, sta_info_destroy(sta); } -struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, - const u8 *addr) +struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, + const u8 *addr) { struct sta_info *sta = sta_info_get(hw_to_local(hw), addr); @@ -810,4 +810,18 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, return NULL; return &sta->sta; } +EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); + +struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, + const u8 *addr) +{ + struct ieee80211_sub_if_data *sdata; + + if (!vif) + return NULL; + + sdata = vif_to_sdata(vif); + + return ieee80211_find_sta_by_hw(&sdata->local->hw, addr); +} EXPORT_SYMBOL(ieee80211_find_sta); -- cgit v1.2.3 From cf7ff8dfe64c8ca8a71b4fcbac357a3476ed1888 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 6 Nov 2009 14:52:44 -0800 Subject: iwlwifi: change debug message to error in failure case Since these messages indicate failure we would be interested in seeing them always. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 905645d15a9b..e8002c1d3eba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -199,13 +199,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) } if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { - IWL_DEBUG_INFO(priv, "Command %s aborted: RF KILL Switch\n", + IWL_ERR(priv, "Command %s aborted: RF KILL Switch\n", get_cmd_string(cmd->id)); ret = -ECANCELED; goto fail; } if (test_bit(STATUS_FW_ERROR, &priv->status)) { - IWL_DEBUG_INFO(priv, "Command %s failed: FW Error\n", + IWL_ERR(priv, "Command %s failed: FW Error\n", get_cmd_string(cmd->id)); ret = -EIO; goto fail; -- cgit v1.2.3 From a3b6bd5bf23c5cd95389e24121da02d2330eaf21 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 6 Nov 2009 14:52:45 -0800 Subject: iwlwifi: allocate 128 bytes linear buffer for rx skb Allocate 128 bytes linear buffer for rx skb. The first 64 bytes is reserved for mac80211 usage (for radiotap header expansion, etc). The frame header starts from the second 64 bytes. Cc: Johannes Berg Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-rx.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 09a7bd2c0be4..26a1134f84a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -564,7 +564,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, return; } - skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC); + skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); if (!skb) { IWL_ERR(priv, "alloc_skb failed\n"); return; @@ -575,6 +575,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, (struct ieee80211_hdr *)rxb_addr(rxb), le32_to_cpu(rx_end->status), stats); + skb_reserve(skb, IWL_LINK_HDR_MAX); skb_add_rx_frag(skb, 0, rxb->page, (void *)rx_hdr->payload - (void *)pkt, len); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index e5339c9ad13e..d2dc7cceb5f2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -937,12 +937,13 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; - skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC); + skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); if (!skb) { IWL_ERR(priv, "alloc_skb failed\n"); return; } + skb_reserve(skb, IWL_LINK_HDR_MAX); skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); /* mac80211 currently doesn't support paged SKB. Convert it to -- cgit v1.2.3 From a643565efcdafdc37638aa5131ced91b2d3ddcb2 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:46 -0800 Subject: iwlwifi: print rx_on config to help debug To help debug rx related issues, if IWL_DEBUG_RADIO flag is set, print the rxon configuration when rxon host command send to uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-core.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.h | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b5fe8f87aa7e..1710815691d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -133,6 +133,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) } memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + iwl_print_rx_config_cmd(priv); return 0; } @@ -228,6 +229,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) } memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); } + iwl_print_rx_config_cmd(priv); iwl_init_sensitivity(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e0b5b4aef41d..f88a1cb7a12b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1328,7 +1328,7 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) EXPORT_SYMBOL(iwl_rx_csa); #ifdef CONFIG_IWLWIFI_DEBUG -static void iwl_print_rx_config_cmd(struct iwl_priv *priv) +void iwl_print_rx_config_cmd(struct iwl_priv *priv) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -1346,6 +1346,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } +EXPORT_SYMBOL(iwl_print_rx_config_cmd); #endif /** * iwl_irq_handle_error - called for HW or SW error interrupt from card diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 9574d8f33537..3f97036ac29b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -579,6 +579,7 @@ int iwl_pci_resume(struct pci_dev *pdev); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_dump_nic_event_log(struct iwl_priv *priv); void iwl_dump_nic_error_log(struct iwl_priv *priv); +void iwl_print_rx_config_cmd(struct iwl_priv *priv); #else static inline void iwl_dump_nic_event_log(struct iwl_priv *priv) { @@ -587,6 +588,10 @@ static inline void iwl_dump_nic_event_log(struct iwl_priv *priv) static inline void iwl_dump_nic_error_log(struct iwl_priv *priv) { } + +static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv) +{ +} #endif void iwl_clear_isr_stats(struct iwl_priv *priv); -- cgit v1.2.3 From f1e3d7d428616c04ef71bee3c2b6f274b8947755 Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Fri, 6 Nov 2009 14:52:47 -0800 Subject: iwlwifi: use only one chain for scan in PS When doing scan in power saving mode, choose only 1 valid RX chain instead of turning all chains on. Signed-off-by: Shanyu Zhao Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-scan.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 1eb0d0bf1fe4..48bc2636a8ef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -581,6 +581,7 @@ static void iwl_bg_request_scan(struct work_struct *data) u8 rate; bool is_active = false; int chan_mod; + u8 active_chains; conf = ieee80211_get_hw_conf(priv->hw); @@ -734,9 +735,22 @@ static void iwl_bg_request_scan(struct work_struct *data) rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); + /* In power save mode use one chain, otherwise use all chains */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + /* rx_ant has been set to all valid chains previously */ + active_chains = rx_ant & + ((u8)(priv->chain_noise_data.active_chains)); + if (!active_chains) + active_chains = rx_ant; + + IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n", + priv->chain_noise_data.active_chains); + + rx_ant = first_antenna(active_chains); + } /* MIMO is not used here, but value is required */ rx_chain |= ANT_ABC << RXON_RX_CHAIN_VALID_POS; - rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; + rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; scan->rx_chain = cpu_to_le16(rx_chain); -- cgit v1.2.3 From b23aa883678aec0f5d9e96c9b3e416ec4fdf735e Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Fri, 6 Nov 2009 14:52:48 -0800 Subject: iwlwifi: use configured valid rx chain for scan Use configured valid rx chains in scan command instead of ANT_ABC, correcting valid rx chain configuration of 4965, should be ANT_ABC instead of ANT_AB. Signed-off-by: Shanyu Zhao Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1ff465ad40d8..faa4c4e2d43c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2228,7 +2228,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, .mod_params = &iwl4965_mod_params, .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, + .valid_rx_ant = ANT_ABC, .pll_cfg_val = 0, .set_l0s = true, .use_bsm = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 48bc2636a8ef..a2b2b8315ff9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -749,7 +749,7 @@ static void iwl_bg_request_scan(struct work_struct *data) rx_ant = first_antenna(active_chains); } /* MIMO is not used here, but value is required */ - rx_chain |= ANT_ABC << RXON_RX_CHAIN_VALID_POS; + rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; -- cgit v1.2.3 From 0748dc1fcd8589c0e215e26112320b76e7c9a262 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:49 -0800 Subject: iwlwifi: no periodic Tx/IQ calibration for 6x00/6x50 series For both 6x00 and 6x50 series devices, periodic Tx IQ calibration is disabled in uCode, driver do not need to set the periodic Tx/IQ calibration bit in calibration command. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 70e117f8d0c4..9ab79546b8a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -166,9 +166,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) BIT(IWL_CALIB_XTAL) | BIT(IWL_CALIB_LO) | BIT(IWL_CALIB_TX_IQ) | - BIT(IWL_CALIB_TX_IQ_PERD) | BIT(IWL_CALIB_BASE_BAND); - return 0; } -- cgit v1.2.3 From a221e6f7b48ee2d9352827af8aec8b49272b5b43 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 6 Nov 2009 14:52:50 -0800 Subject: iwlwifi: don't double-activate queue 4 The fourth queue (command queue) is already activated in the loop above that also maps it to the command FIFO and therefore doesn't need to be marked as activated again. Also change the TODO comment to be accurate -- we need to initialise the _queues_, not FIFOs, and map them to device FIFOs. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 910217f0ad8a..6ea5e2dc273c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -661,9 +661,13 @@ int iwl5000_alive_notify(struct iwl_priv *priv) iwl_txq_ctx_activate(priv, i); iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0); } - /* TODO - need to initialize those FIFOs inside the loop above, - * not only mark them as active */ - iwl_txq_ctx_activate(priv, 4); + + /* + * TODO - need to initialize these queues and map them to FIFOs + * in the loop above, not only mark them as active. We do this + * because we want the first aggregation queue to be queue #10, + * but do not use 8 or 9 otherwise yet. + */ iwl_txq_ctx_activate(priv, 7); iwl_txq_ctx_activate(priv, 8); iwl_txq_ctx_activate(priv, 9); -- cgit v1.2.3 From 1a716557a5ed3b814cb32b8be79848d53e470871 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 6 Nov 2009 14:52:51 -0800 Subject: iwlwifi: fix FIFO vs. queue confusion When I added that code setting the swq_id, I evidently did not understand the distinction between FIFO and TX queue yet and added code to compare a queue ID and a FIFO number, which is bogus. However, the code there need not be this specific, it can just set all queues to the identity mapping which will be overwritten by the aggregation queue code. As a bit of defensive coding, don't assign an swq_id to the command queue so that if we ever use it for frames we notice quickly. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 5 +++-- drivers/net/wireless/iwlwifi/iwl-tx.c | 9 +++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cb2642c18da4..b4e814543039 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -324,8 +324,9 @@ struct iwl_channel_info { #define IWL_MIN_NUM_QUEUES 10 /* - * uCode queue management definitions ... - * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00. + * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00, + * the driver maps it into the appropriate device FIFO for the + * uCode. */ #define IWL_CMD_QUEUE_NUM 4 diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 05e75109d842..905ceca88b95 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -364,8 +364,13 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, txq->need_update = 0; - /* aggregation TX queues will get their ID when aggregation begins */ - if (txq_id <= IWL_TX_FIFO_AC3) + /* + * Aggregation TX queues will get their ID when aggregation begins; + * they overwrite the setting done here. The command FIFO doesn't + * need an swq_id so don't set one to catch errors, all others can + * be set up to the identity mapping. + */ + if (txq_id != IWL_CMD_QUEUE_NUM) txq->swq_id = txq_id; /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise -- cgit v1.2.3 From bed0a68f98d93c0abdc96b4c290a92c80234c182 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:52 -0800 Subject: iwlwifi: remove un-used parameter Remove un-used parameter "recovery_rxon" from "priv" data structure Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b4e814543039..997564584c71 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1087,8 +1087,6 @@ struct iwl_priv { const struct iwl_rxon_cmd active_rxon; struct iwl_rxon_cmd staging_rxon; - struct iwl_rxon_cmd recovery_rxon; - /* 1st responses from initialize and runtime uCode images. * 4965's initialize alive response contains some calibration data. */ struct iwl_init_alive_resp card_alive_init; -- cgit v1.2.3 From 681988653ed46a14032ac5fe2ee84eaae314b72e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 6 Nov 2009 14:52:53 -0800 Subject: iwlwifi: add FIFO usage for 5000 This is part of the code, but the comment doesn't have it, add pointers to the code and the FIFO usage for 5000 and up. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-prph.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index d393e8f02102..6d95832db06d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -254,7 +254,8 @@ * device. A queue maps to only one (selectable by driver) Tx DMA channel, * but one DMA channel may take input from several queues. * - * Tx DMA channels have dedicated purposes. For 4965, they are used as follows: + * Tx DMA channels have dedicated purposes. For 4965, they are used as follows + * (cf. default_queue_to_tx_fifo in iwl-4965.c): * * 0 -- EDCA BK (background) frames, lowest priority * 1 -- EDCA BE (best effort) frames, normal priority @@ -265,9 +266,21 @@ * 6 -- HCCA long frames * 7 -- not used by driver (device-internal only) * + * For 5000 series and up, they are used slightly differently + * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c): + * + * 0 -- EDCA BK (background) frames, lowest priority + * 1 -- EDCA BE (best effort) frames, normal priority + * 2 -- EDCA VI (video) frames, higher priority + * 3 -- EDCA VO (voice) and management frames, highest priority + * 4 -- (TBD) + * 5 -- HCCA short frames + * 6 -- HCCA long frames + * 7 -- Commands + * * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6. - * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to - * support 11n aggregation via EDCA DMA channels. + * In addition, driver can map the remaining queues to Tx DMA/FIFO + * channels 0-3 to support 11n aggregation via EDCA DMA channels. * * The driver sets up each queue to work in one of two modes: * -- cgit v1.2.3 From 0924e519a3a18ffbfaa043f4a2c369140c5a235c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:54 -0800 Subject: iwlwifi: fix for channel switch Different channel has different configuration, need to pass correct configuration to uCode when send "channel switch" command to uCode. Invalid configuration will cause sysassert in uCode and produce un-expected result. Even it is a very small windows, but we also need to consider and handle the case if commit_rxon occurred before the "channel switch announcement" notification received from uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 12 +++++---- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 +++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 6 +++-- drivers/net/wireless/iwlwifi/iwl-agn.c | 11 ++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 45 +++++++++++++++++++++------------ drivers/net/wireless/iwlwifi/iwl-dev.h | 13 ++++++++++ 6 files changed, 68 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index faa4c4e2d43c..1d22ea390c00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1449,14 +1449,14 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) is_ht40 = is_ht40_channel(priv->staging_rxon.flags); if (is_ht40 && - (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) + (priv->staging_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) ctrl_chan_high = 1; cmd.band = band; cmd.expect_beacon = 0; cmd.channel = cpu_to_le16(channel); - cmd.rxon_flags = priv->active_rxon.flags; - cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.rxon_flags = priv->staging_rxon.flags; + cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); if (ch_info) cmd.expect_beacon = is_channel_radar(ch_info); @@ -1473,8 +1473,10 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) return rc; } - rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); - return rc; + priv->switch_rxon.channel = cpu_to_le16(channel); + priv->switch_rxon.switch_in_progress = true; + + return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); } /** diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 6ea5e2dc273c..6eaf26b07636 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1391,8 +1391,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) priv->active_rxon.channel, channel); cmd.band = priv->band == IEEE80211_BAND_2GHZ; cmd.channel = cpu_to_le16(channel); - cmd.rxon_flags = priv->active_rxon.flags; - cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.rxon_flags = priv->staging_rxon.flags; + cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); ch_info = iwl_get_channel_info(priv, priv->band, channel); if (ch_info) @@ -1402,6 +1402,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) priv->active_rxon.channel, channel); return -EFAULT; } + priv->switch_rxon.channel = cpu_to_le16(channel); + priv->switch_rxon.switch_in_progress = true; return iwl_send_cmd_sync(priv, &hcmd); } diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 9ab79546b8a4..1f769ea23636 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -186,8 +186,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) cmd.band = priv->band == IEEE80211_BAND_2GHZ; cmd.channel = cpu_to_le16(channel); - cmd.rxon_flags = priv->active_rxon.flags; - cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.rxon_flags = priv->staging_rxon.flags; + cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); ch_info = iwl_get_channel_info(priv, priv->band, channel); if (ch_info) @@ -197,6 +197,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) priv->active_rxon.channel, channel); return -EFAULT; } + priv->switch_rxon.channel = cpu_to_le16(channel); + priv->switch_rxon.switch_in_progress = true; return iwl_send_cmd_sync(priv, &hcmd); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1710815691d5..7bdedf61dd36 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -122,6 +122,17 @@ int iwl_commit_rxon(struct iwl_priv *priv) return -EINVAL; } + /* + * receive commit_rxon request + * abort any previous channel switch if still in process + */ + if (priv->switch_rxon.switch_in_progress && + (priv->switch_rxon.channel != priv->staging_rxon.channel)) { + IWL_DEBUG_11H(priv, "abort channel switch on %d\n", + le16_to_cpu(priv->switch_rxon.channel)); + priv->switch_rxon.switch_in_progress = false; + } + /* If we don't need to send a full RXON, we can use * iwl_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index f88a1cb7a12b..e0edc607e33f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1316,14 +1316,19 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; struct iwl_csa_notification *csa = &(pkt->u.csa_notif); - if (!le32_to_cpu(csa->status)) { - rxon->channel = csa->channel; - priv->staging_rxon.channel = csa->channel; - IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", - le16_to_cpu(csa->channel)); - } else - IWL_ERR(priv, "CSA notif (fail) : channel %d\n", - le16_to_cpu(csa->channel)); + if (priv->switch_rxon.switch_in_progress) { + if (!le32_to_cpu(csa->status) && + (csa->channel == priv->switch_rxon.channel)) { + rxon->channel = csa->channel; + priv->staging_rxon.channel = csa->channel; + IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", + le16_to_cpu(csa->channel)); + } else + IWL_ERR(priv, "CSA notif (fail) : channel %d\n", + le16_to_cpu(csa->channel)); + + priv->switch_rxon.switch_in_progress = false; + } } EXPORT_SYMBOL(iwl_rx_csa); @@ -2690,14 +2695,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) goto set_ch_out; } - if (iwl_is_associated(priv) && - (le16_to_cpu(priv->active_rxon.channel) != ch) && - priv->cfg->ops->lib->set_channel_switch) { - ret = priv->cfg->ops->lib->set_channel_switch(priv, - ch); - goto out; - } - spin_lock_irqsave(&priv->lock, flags); /* Configure HT40 channels */ @@ -2732,6 +2729,22 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) iwl_set_flags_for_band(priv, conf->channel->band); spin_unlock_irqrestore(&priv->lock, flags); + if (iwl_is_associated(priv) && + (le16_to_cpu(priv->active_rxon.channel) != ch) && + priv->cfg->ops->lib->set_channel_switch) { + iwl_set_rate(priv); + /* + * at this point, staging_rxon has the + * configuration for channel switch + */ + ret = priv->cfg->ops->lib->set_channel_switch(priv, + ch); + if (!ret) { + iwl_print_rx_config_cmd(priv); + goto out; + } + priv->switch_rxon.switch_in_progress = false; + } set_ch_out: /* The list of supported rates and rate mask can be different * for each band; since the band may have changed, reset diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 997564584c71..9a19a3d1f704 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -994,6 +994,17 @@ struct traffic_stats { }; #endif +/* + * iwl_switch_rxon: "channel switch" structure + * + * @ switch_in_progress: channel switch in progress + * @ channel: new channel + */ +struct iwl_switch_rxon { + bool switch_in_progress; + __le16 channel; +}; + struct iwl_priv { /* ieee device used by generic ieee processing code */ @@ -1087,6 +1098,8 @@ struct iwl_priv { const struct iwl_rxon_cmd active_rxon; struct iwl_rxon_cmd staging_rxon; + struct iwl_switch_rxon switch_rxon; + /* 1st responses from initialize and runtime uCode images. * 4965's initialize alive response contains some calibration data. */ struct iwl_init_alive_resp card_alive_init; -- cgit v1.2.3 From 740e7f51c226076d8f8ccb203d9ba6258a5bcec7 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:55 -0800 Subject: iwlwifi: drop non-production PCI-IDs Remove the support for all the PCI_IDs never make into production Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 98 +-------------------------------- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 --- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +- 3 files changed, 2 insertions(+), 108 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 1f769ea23636..f732f6d194a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -90,11 +90,7 @@ static void iwl6000_nic_config(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); /* no locking required for register write */ - if (priv->cfg->pa_type == IWL_PA_HYBRID) { - /* 2x2 hybrid phy type */ - iwl_write32(priv, CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB); - } else if (priv->cfg->pa_type == IWL_PA_INTERNAL) { + if (priv->cfg->pa_type == IWL_PA_INTERNAL) { /* 2x2 IPA phy type */ iwl_write32(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); @@ -279,98 +275,6 @@ static struct iwl_ops iwl6050_ops = { .led = &iwlagn_led_ops, }; - -/* - * "h": Hybrid configuration, use both internal and external Power Amplifier - */ -struct iwl_cfg iwl6000h_2agn_cfg = { - .name = "6000 Series 2x2 AGN", - .fw_name_pre = IWL6000_FW_PRE, - .ucode_api_max = IWL6000_UCODE_API_MAX, - .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .num_of_queues = IWL50_NUM_QUEUES, - .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, - .mod_params = &iwl50_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_HYBRID, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_ht = true, /* use rts/cts protection */ - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, -}; - -struct iwl_cfg iwl6000h_2abg_cfg = { - .name = "6000 Series 2x2 ABG", - .fw_name_pre = IWL6000_FW_PRE, - .ucode_api_max = IWL6000_UCODE_API_MAX, - .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl6000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .num_of_queues = IWL50_NUM_QUEUES, - .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, - .mod_params = &iwl50_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_HYBRID, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, -}; - -struct iwl_cfg iwl6000h_2bg_cfg = { - .name = "6000 Series 2x2 BG", - .fw_name_pre = IWL6000_FW_PRE, - .ucode_api_max = IWL6000_UCODE_API_MAX, - .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_G, - .ops = &iwl6000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .num_of_queues = IWL50_NUM_QUEUES, - .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, - .mod_params = &iwl50_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_HYBRID, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, -}; - /* * "i": Internal configuration, use internal Power Amplifier */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7bdedf61dd36..ad8a348b1c81 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3452,14 +3452,6 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, /* 6x00 Series */ - {IWL_PCI_DEVICE(0x008D, 0x1301, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x008D, 0x1321, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x008D, 0x1326, iwl6000h_2abg_cfg)}, - {IWL_PCI_DEVICE(0x008D, 0x1306, iwl6000h_2abg_cfg)}, - {IWL_PCI_DEVICE(0x008D, 0x1307, iwl6000h_2bg_cfg)}, - {IWL_PCI_DEVICE(0x008E, 0x1311, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x008E, 0x1316, iwl6000h_2abg_cfg)}, - {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9a19a3d1f704..9dea8fa08c0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -927,13 +927,11 @@ enum iwl_access_mode { /** * enum iwl_pa_type - Power Amplifier type * @IWL_PA_SYSTEM: based on uCode configuration - * @IWL_PA_HYBRID: use both Internal and external PA * @IWL_PA_INTERNAL: use Internal only */ enum iwl_pa_type { IWL_PA_SYSTEM = 0, - IWL_PA_HYBRID = 1, - IWL_PA_INTERNAL = 2, + IWL_PA_INTERNAL = 1, }; /* interrupt statistics */ -- cgit v1.2.3 From 6762f07fd55ff5e588aa5f0a1b70efe8e268a2e8 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:56 -0800 Subject: iwlwifi: do not base station's sm_ps setting on AP Do not use AP's SM_PS setting for our own SM_PS setting. Reported-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e0edc607e33f..d09e74815323 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2316,12 +2316,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; maxstreams += 1; - ht_conf->sm_ps = - (u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS) - >> 2); - IWL_DEBUG_MAC80211(priv, "sm_ps: 0x%x\n", - ht_conf->sm_ps); - if ((ht_cap->mcs.rx_mask[1] == 0) && (ht_cap->mcs.rx_mask[2] == 0)) ht_conf->single_chain_sufficient = true; -- cgit v1.2.3 From 84c4069232a671b3739387949d5cb588dacbd24a Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:52:57 -0800 Subject: iwlwifi: Limit size of Event Log dump If device provides bad values for Event Log parameters (due to being asleep or SRAM corruption, etc.), the size can be very, very large (e.g. 0xa5a5a5a5), which can flood system log. Sanity-check capacity and next_entry values and limit to reasonable size dump. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 15 +++++++++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 15 +++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ad8a348b1c81..9c40742727a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1702,6 +1702,9 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, } } +/* For sanity check only. Actual size is determined by uCode, typ. 512 */ +#define MAX_EVENT_LOG_SIZE (512) + void iwl_dump_nic_event_log(struct iwl_priv *priv) { u32 base; /* SRAM byte address of event log header */ @@ -1727,6 +1730,18 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); + if (capacity > MAX_EVENT_LOG_SIZE) { + IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n", + capacity, MAX_EVENT_LOG_SIZE); + capacity = MAX_EVENT_LOG_SIZE; + } + + if (next_entry > MAX_EVENT_LOG_SIZE) { + IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", + next_entry, MAX_EVENT_LOG_SIZE); + next_entry = MAX_EVENT_LOG_SIZE; + } + size = num_wraps ? capacity : next_entry; /* bail out if nothing in log */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 23b31e6dcacd..a17afe01c0c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1603,6 +1603,9 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, } } +/* For sanity check only. Actual size is determined by uCode, typ. 512 */ +#define IWL3945_MAX_EVENT_LOG_SIZE (512) + void iwl3945_dump_nic_event_log(struct iwl_priv *priv) { u32 base; /* SRAM byte address of event log header */ @@ -1624,6 +1627,18 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv) num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); + if (capacity > IWL3945_MAX_EVENT_LOG_SIZE) { + IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n", + capacity, IWL3945_MAX_EVENT_LOG_SIZE); + capacity = IWL3945_MAX_EVENT_LOG_SIZE; + } + + if (next_entry > IWL3945_MAX_EVENT_LOG_SIZE) { + IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", + next_entry, IWL3945_MAX_EVENT_LOG_SIZE); + next_entry = IWL3945_MAX_EVENT_LOG_SIZE; + } + size = num_wraps ? capacity : next_entry; /* bail out if nothing in log */ -- cgit v1.2.3 From e585447189123de627ecbfaccab9d7a3328a5dd8 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:52:58 -0800 Subject: iwlwifi: speed up event log dumps Take advantage of device's auto-increment for SRAM reads to eliminate extra write address accesses. Grab/release NIC access before/after entire read sequence, rather than for each read individually. After a quick check of dmesg logs, this seems to double Event Log dump speed, reducing from about 20 milliseconds to about 10 milliseconds for 512 entries using 3945. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 22 ++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl3945-base.c | 22 ++++++++++++++++------ 2 files changed, 32 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 9c40742727a2..2abd1f5b5eea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1666,6 +1666,7 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ u32 ptr; /* SRAM byte address of log data */ u32 ev, time, data; /* event log data */ + unsigned long reg_flags; if (num_events == 0) return; @@ -1681,25 +1682,34 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + /* Make sure device is powered up for SRAM reads */ + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + + /* Set starting address; reads will auto-increment */ + _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + rmb(); + /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - time = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); + ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); } else { - data = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); + data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", time, data, ev); trace_iwlwifi_dev_ucode_event(priv, time, data, ev); } } + + /* Allow device to power down */ + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } /* For sanity check only. Actual size is determined by uCode, typ. 512 */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a17afe01c0c0..92ecdd9abd9f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1570,6 +1570,7 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ u32 ptr; /* SRAM byte address of log data */ u32 ev, time, data; /* event log data */ + unsigned long reg_flags; if (num_events == 0) return; @@ -1583,24 +1584,33 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + /* Make sure device is powered up for SRAM reads */ + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + + /* Set starting address; reads will auto-increment */ + _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + rmb(); + /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - time = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); + ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); } else { - data = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); + data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev); trace_iwlwifi_dev_ucode_event(priv, time, data, ev); } } + + /* Allow device to power down */ + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } /* For sanity check only. Actual size is determined by uCode, typ. 512 */ -- cgit v1.2.3 From 2a3b793d6a0ff30ad4a541230a6dba2ecb6fff1b Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:52:59 -0800 Subject: iwlwifi: Update comments for struct iwl_ssid_ie Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index b62c90ec9e1e..2857287be4fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2566,9 +2566,10 @@ struct iwl_scan_channel { /** * struct iwl_ssid_ie - directed scan network information element * - * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field - * in struct iwl_scan_channel; each channel may select different ssids from - * among the 4 entries. SSID IEs get transmitted in reverse order of entry. + * Up to 20 of these may appear in REPLY_SCAN_CMD (Note: Only 4 are in + * 3945 SCAN api), selected by "type" bit field in struct iwl_scan_channel; + * each channel may select different ssids from among the 20 (4) entries. + * SSID IEs get transmitted in reverse order of entry. */ struct iwl_ssid_ie { u8 id; -- cgit v1.2.3 From a7e6611034530fce62f5499f77dd4fb6cde4d130 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:53:00 -0800 Subject: iwlwifi: Add comments about MAC_ACCESS_REQ Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-io.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 0a078b082833..d0a358c9d96b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -200,6 +200,26 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv) /* this bit wakes up the NIC */ _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* + * These bits say the device is running, and should keep running for + * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), + * but they do not indicate that embedded SRAM is restored yet; + * 3945 and 4965 have volatile SRAM, and must save/restore contents + * to/from host DRAM when sleeping/waking for power-saving. + * Each direction takes approximately 1/4 millisecond; with this + * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a + * series of register accesses are expected (e.g. reading Event Log), + * to keep device from sleeping. + * + * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that + * SRAM is okay/restored. We don't check that here because this call + * is just for hardware register access; but GP1 MAC_SLEEP check is a + * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). + * + * 5000 series and later (including 1000 series) have non-volatile SRAM, + * and do not save/restore SRAM when power cycling. + */ ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | -- cgit v1.2.3 From 8756990f99ecdfe64ed32cce878e36bddc16bdcc Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:53:01 -0800 Subject: iwlagn: update write pointers in iwl_irq_tasklet() Follow-up to "update write pointers for all tx queues after wakeup"; that patch changed iwl_irq_tasklet_legacy(), but not iwl_irq_tasklet(), so newer devices were not covered. Comments from original patch: Wakeup interrupt has been updating write pointers (indexes, actually) only for tx queues 0-5. This is adequate just for 3945, but inadequate for other devices, all of which have more tx queues. Now updating all tx/command queues, so device can be aware of all new tx and host commands enqueued while device was asleep. This can potentially improve data traffic bandwidth and/or latency. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2abd1f5b5eea..8198e14b8fad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1084,6 +1084,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) u32 inta = 0; u32 handled = 0; unsigned long flags; + u32 i; #ifdef CONFIG_IWLWIFI_DEBUG u32 inta_mask; #endif @@ -1194,12 +1195,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_WAKEUP) { IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - iwl_txq_update_write_ptr(priv, &priv->txq[0]); - iwl_txq_update_write_ptr(priv, &priv->txq[1]); - iwl_txq_update_write_ptr(priv, &priv->txq[2]); - iwl_txq_update_write_ptr(priv, &priv->txq[3]); - iwl_txq_update_write_ptr(priv, &priv->txq[4]); - iwl_txq_update_write_ptr(priv, &priv->txq[5]); + for (i = 0; i < priv->hw_params.max_txq_num; i++) + iwl_txq_update_write_ptr(priv, &priv->txq[i]); priv->isr_stats.wakeup++; -- cgit v1.2.3 From f060face819401fb1f6456d362c5bc6672bba655 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:53:02 -0800 Subject: iwlwifi: Fix issue on file transfer stalled in HT mode Turn on RTS/CTS for HT to prevent uCode TX fifo underrun This is fix for http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2103 Signed-off-by: Wey-Yi Guy Tested-by: Jiajia Zheng Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 1e387b9dce1e..8f82537045bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -170,6 +170,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .shadow_ram_support = false, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, }; -- cgit v1.2.3 From 309e731a619bee28ace609b0c4c3a0029b7e5394 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:53:03 -0800 Subject: iwlwifi: MAC_ACCESS_REQ cleanup Add txq_id info to "Tx queue requesting wakeup" debug message Add "Rx queue requesting wakeup" debug message Move clear of CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ to be after nearby iwl_write_prph(), since iwl_write_prph() sets it and clears it. Almost removed it entirely, but just making sure in case someone removes the iwl_write_prph()! Also remove unneeded priv->lock usage; this is now handled by priv->reg_lock within iwl_clear_bit(). Join a couple of lines that had unneeded line returns. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 12 +++++------- drivers/net/wireless/iwlwifi/iwl-rx.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-tx.c | 3 ++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 ++--- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8198e14b8fad..da0b38e866ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1934,19 +1934,17 @@ static void __iwl_down(struct iwl_priv *priv) /* device going down, Stop using ICT table */ iwl_disable_ict(priv); - spin_lock_irqsave(&priv->lock, flags); - iwl_clear_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - spin_unlock_irqrestore(&priv->lock, flags); iwl_txq_ctx_stop(priv); iwl_rxq_stop(priv); - iwl_write_prph(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - + /* Power-down device's busmaster DMA clocks */ + iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); udelay(5); + /* Make sure (redundant) we've released our request to stay awake */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + /* Stop the device, and put it in low power state */ priv->cfg->ops->lib->apm_ops.stop(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index d2dc7cceb5f2..61b3b0e6ed73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -140,6 +140,8 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO(priv, "Rx queue requesting wakeup, GP1 = 0x%x\n", + reg); iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); goto exit_unlock; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 905ceca88b95..9370e062000d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -96,7 +96,8 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO(priv, "Requesting wakeup, GP1 = 0x%x\n", reg); + IWL_DEBUG_INFO(priv, "Tx queue %d requesting wakeup, GP1 = 0x%x\n", + txq_id, reg); iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 92ecdd9abd9f..05f118529fea 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2600,9 +2600,8 @@ static void __iwl3945_down(struct iwl_priv *priv) iwl3945_hw_txq_ctx_stop(priv); iwl3945_hw_rxq_stop(priv); - iwl_write_prph(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - + /* Power-down device's busmaster DMA clocks */ + iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); udelay(5); /* Stop the device, and put it in low power state */ -- cgit v1.2.3 From ddd21046e7b5e112b5a4722b7e071ae9d4c96a2b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 11 Nov 2009 13:04:42 -0800 Subject: iwlwifi: fix iwl1000 "RTS/CTS for HT" merge damage I may have botched my merge conflict resolution instructions for Dave... Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 1e387b9dce1e..8f82537045bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -170,6 +170,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .shadow_ram_support = false, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, }; -- cgit v1.2.3 From d20a80f0e6eb9a4f31489a0518a9ba0754eeee12 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 18 Nov 2009 08:25:25 +0000 Subject: drivers/net/wireless/iwlwifi: remove exceptional & on function name In this file, function names are otherwise used as pointers without &. A simplified version of the semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r@ identifier f; @@ f(...) { ... } @@ identifier r.f; @@ - &f + f // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index dc81e19674f7..d4b49883b30e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -355,7 +355,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, init_timer(&rs_sta->rate_scale_flush); rs_sta->rate_scale_flush.data = (unsigned long)rs_sta; - rs_sta->rate_scale_flush.function = &iwl3945_bg_rate_scale_flush; + rs_sta->rate_scale_flush.function = iwl3945_bg_rate_scale_flush; for (i = 0; i < IWL_RATE_COUNT_3945; i++) iwl3945_clear_window(&rs_sta->win[i]); -- cgit v1.2.3 From 85f0d9e87794818356146996826b829100daa6bc Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:23 -0800 Subject: iwlwifi: validate enhanced tx power entry Validate enhanced tx power entry read from EEPROM before applying the tx power value. Different versions of EEPROM might contain different size of table; always a good idea to make sure the entry is valid before applying to the targeted channel. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 8a0709e81a9f..143728c6382e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -913,6 +913,16 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *) iwl_eeprom_query_addr(priv, offset); + /* + * check for valid entry - + * different version of EEPROM might contain different set + * of enhanced tx power table + * always check for valid entry before process + * the information + */ + if (!enhanced_txpower->common || enhanced_txpower->reserved) + continue; + for (element = 0; element < eeprom_section_count; element++) { if (enhinfo[section].is_common) max_txpower_avg = diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 5ba5a4e9e49a..5cd2b66bbe45 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -127,19 +127,21 @@ struct iwl_eeprom_channel { * 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 + * @common: (desc + channel) not used by driver, should _NOT_ be "zero" * @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 + * @reserved: not used, should be "zero" * @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; + u16 common; s8 chain_a_max; s8 chain_b_max; s8 chain_c_max; - s8 reserved1; + s8 reserved; s8 mimo2_max; s8 mimo3_max; } __attribute__ ((packed)); -- cgit v1.2.3 From 85bb174a386850c8a43e8d107af47de3c910be03 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:24 -0800 Subject: iwlwifi: disable coex until implementation ready for 6x50 Temporary disable the coex function for wifi/wimax for 6x50 series until the full implementation ready. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index f732f6d194a0..72ed944843b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -395,7 +395,6 @@ struct iwl_cfg iwl6050_2agn_cfg = { .adv_thermal_throttle = true, .support_ct_kill_exit = true, .support_sm_ps = true, - .support_wimax_coexist = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -425,7 +424,6 @@ struct iwl_cfg iwl6050_2abg_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .support_wimax_coexist = true, }; struct iwl_cfg iwl6000_3agn_cfg = { -- cgit v1.2.3 From d7d144012a2949cf7f8eed758013adadf5e5a82e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:25 -0800 Subject: iwlwifi: remove unused parameter from iwl_channel_info Number of HT40 power parameters are not used; remove those from iwl_channel_info data structure Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 --- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 7 ------- 2 files changed, 10 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9dea8fa08c0e..d0f091519793 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -295,9 +295,6 @@ struct iwl_channel_info { /* 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_* */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 143728c6382e..e42eb6499f0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -751,9 +751,6 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, 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; @@ -840,8 +837,6 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv, (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++; } @@ -881,8 +876,6 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, (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; } -- cgit v1.2.3 From a8a9a159bf907ef02aca2e316025e427f315e82a Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:26 -0800 Subject: iwlwifi: drop non-production PCI-IDs for 6x50 series drop the non-production PCI-IDs for 6x50 series Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 32 -------------------------------- drivers/net/wireless/iwlwifi/iwl-agn.c | 3 --- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 3 files changed, 36 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 72ed944843b0..4ab9897f4fe1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -456,37 +456,5 @@ struct iwl_cfg iwl6000_3agn_cfg = { .support_ct_kill_exit = true, }; -struct iwl_cfg iwl6050_3agn_cfg = { - .name = "6050 Series 3x3 AGN", - .fw_name_pre = IWL6050_FW_PRE, - .ucode_api_max = IWL6050_UCODE_API_MAX, - .ucode_api_min = IWL6050_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6050_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6050_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .num_of_queues = IWL50_NUM_QUEUES, - .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, - .mod_params = &iwl50_mod_params, - .valid_tx_ant = ANT_ABC, - .valid_rx_ant = ANT_ABC, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x50, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_ht = true, /* use rts/cts protection */ - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, - .support_sm_ps = true, - .support_wimax_coexist = true, -}; - MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index da0b38e866ba..6532e9e68951 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3484,13 +3484,10 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)}, /* 6x50 WiFi/WiMax Series */ - {IWL_PCI_DEVICE(0x0086, 0x1101, iwl6050_3agn_cfg)}, - {IWL_PCI_DEVICE(0x0086, 0x1121, iwl6050_3agn_cfg)}, {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)}, {IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)}, {IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)}, {IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)}, - {IWL_PCI_DEVICE(0x0088, 0x1111, iwl6050_3agn_cfg)}, {IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)}, {IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index d0f091519793..273adee81cf1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -64,7 +64,6 @@ extern struct iwl_cfg iwl6000i_2bg_cfg; extern struct iwl_cfg iwl6000_3agn_cfg; extern struct iwl_cfg iwl6050_2agn_cfg; extern struct iwl_cfg iwl6050_2abg_cfg; -extern struct iwl_cfg iwl6050_3agn_cfg; extern struct iwl_cfg iwl1000_bgn_cfg; extern struct iwl_cfg iwl1000_bg_cfg; -- cgit v1.2.3 From 7d2ed110a80991849a2824a6dc3c063ffca9dbe4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:27 -0800 Subject: iwlwifi: remove external reference for non-exist data structure Number of data structure for 6000 series no longer in production, the data structure already being removed; also need to remove the external reference define in iwl-dev.h Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 273adee81cf1..774a315996e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -55,9 +55,6 @@ extern struct iwl_cfg iwl5350_agn_cfg; extern struct iwl_cfg iwl5100_bg_cfg; extern struct iwl_cfg iwl5100_abg_cfg; extern struct iwl_cfg iwl5150_agn_cfg; -extern struct iwl_cfg iwl6000h_2agn_cfg; -extern struct iwl_cfg iwl6000h_2abg_cfg; -extern struct iwl_cfg iwl6000h_2bg_cfg; extern struct iwl_cfg iwl6000i_2agn_cfg; extern struct iwl_cfg iwl6000i_2abg_cfg; extern struct iwl_cfg iwl6000i_2bg_cfg; -- cgit v1.2.3 From ef8d5529b015d4c5db7fad1adfc91edfd5abad56 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:28 -0800 Subject: iwlwifi: update reply_statistics_cmd with 'clear' parameter When issue REPLY_STATISTICS_CMD to uCode, two possible flag can be set in the configuration flags bit 0: Clear statistics 0: Do not clear Statistics counters 1: Clear to zero Statistics counters Allow "clear" parameter to be set from the caller. Add debugfs file to clear the statistics counters to help monitor and debug the uCode behavior. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ++--- drivers/net/wireless/iwlwifi/iwl-calib.c | 2 +- drivers/net/wireless/iwlwifi/iwl-commands.h | 4 +++ drivers/net/wireless/iwlwifi/iwl-core.c | 21 ++++++++++------ drivers/net/wireless/iwlwifi/iwl-core.h | 5 +++- drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 39 +++++++++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-power.c | 2 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 18 +++++++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 10 files changed, 77 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6532e9e68951..f586e7e83131 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -612,7 +612,7 @@ static void iwl_bg_statistics_periodic(unsigned long data) if (!iwl_is_ready_rf(priv)) return; - iwl_send_statistics_request(priv, CMD_ASYNC); + iwl_send_statistics_request(priv, CMD_ASYNC, false); } static void iwl_rx_beacon_notif(struct iwl_priv *priv, @@ -729,7 +729,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) * statistics request from the host as well as for the periodic * statistics notifications (after received beacons) from the uCode. */ - priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics; + priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_reply_statistics; priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; iwl_setup_spectrum_handlers(priv); @@ -2892,7 +2892,7 @@ static ssize_t show_statistics(struct device *d, return -EAGAIN; mutex_lock(&priv->mutex); - rc = iwl_send_statistics_request(priv, 0); + rc = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (rc) { diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index d994de7438d8..95a57b36a7ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -900,7 +900,7 @@ void iwl_reset_run_time_calib(struct iwl_priv *priv) /* Ask for statistics now, the uCode will send notification * periodically after association */ - iwl_send_statistics_request(priv, CMD_ASYNC); + iwl_send_statistics_request(priv, CMD_ASYNC, true); } EXPORT_SYMBOL(iwl_reset_run_time_calib); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 2857287be4fd..6e23a2b5cb8a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3071,6 +3071,10 @@ struct statistics_general { __le32 reserved3; } __attribute__ ((packed)); +#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0) +#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1) +#define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2) + /* * REPLY_STATISTICS_CMD = 0x9c, * 3945 and 4965 identical. diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d09e74815323..1736c60c3e21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1990,16 +1990,21 @@ int iwl_send_bt_config(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_send_bt_config); -int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) +int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) { - u32 stat_flags = 0; - struct iwl_host_cmd cmd = { - .id = REPLY_STATISTICS_CMD, - .flags = flags, - .len = sizeof(stat_flags), - .data = (u8 *) &stat_flags, + struct iwl_statistics_cmd statistics_cmd = { + .configuration_flags = + clear ? IWL_STATS_CONF_CLEAR_STATS : 0, }; - return iwl_send_cmd(priv, &cmd); + + if (flags & CMD_ASYNC) + return iwl_send_cmd_pdu_async(priv, REPLY_STATISTICS_CMD, + sizeof(struct iwl_statistics_cmd), + &statistics_cmd, NULL); + else + return iwl_send_cmd_pdu(priv, REPLY_STATISTICS_CMD, + sizeof(struct iwl_statistics_cmd), + &statistics_cmd); } EXPORT_SYMBOL(iwl_send_statistics_request); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3f97036ac29b..584a376b96c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -425,6 +425,8 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); +void iwl_reply_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); /* TX helpers */ @@ -669,7 +671,8 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv) extern void iwl_rf_kill_ct_config(struct iwl_priv *priv); extern int iwl_send_bt_config(struct iwl_priv *priv); -extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags); +extern int iwl_send_statistics_request(struct iwl_priv *priv, + u8 flags, bool clear); extern int iwl_verify_ucode(struct iwl_priv *priv); extern int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_link_quality_cmd *lq, u8 flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 96c92eab692a..25a0e73314f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -107,6 +107,7 @@ struct iwl_debugfs { struct dentry *file_chain_noise; struct dentry *file_tx_power; struct dentry *file_power_save_status; + struct dentry *file_clear_statistics; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 8784911fd56e..45a5edd1b1a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1042,10 +1042,6 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, 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) { @@ -1092,7 +1088,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, /* make request to uCode to retrieve statistics information */ mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, 0); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (ret) { @@ -1398,7 +1394,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, /* make request to uCode to retrieve statistics information */ mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, 0); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (ret) { @@ -1542,7 +1538,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, /* make request to uCode to retrieve statistics information */ mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, 0); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (ret) { @@ -1770,7 +1766,7 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file, else { /* make request to uCode to retrieve statistics information */ mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, 0); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (ret) { @@ -1828,6 +1824,30 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t iwl_dbgfs_clear_statistics_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 clear; + + 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", &clear) != 1) + return -EFAULT; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + iwl_send_statistics_request(priv, CMD_SYNC, true); + mutex_unlock(&priv->mutex); + + return count; +} + DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1840,6 +1860,7 @@ DEBUGFS_READ_FILE_OPS(sensitivity); DEBUGFS_READ_FILE_OPS(chain_noise); DEBUGFS_READ_FILE_OPS(tx_power); DEBUGFS_READ_FILE_OPS(power_save_status); +DEBUGFS_WRITE_FILE_OPS(clear_statistics); /* * Create the debugfs files and directories @@ -1888,6 +1909,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(tx_queue, debug); DEBUGFS_ADD_FILE(tx_power, debug); DEBUGFS_ADD_FILE(power_save_status, debug); + DEBUGFS_ADD_FILE(clear_statistics, 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); @@ -1941,6 +1963,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_clear_statistics); 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); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 9bce2c1625e3..8ccc0bb1d9ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -506,7 +506,7 @@ static void iwl_prepare_ct_kill_task(struct iwl_priv *priv) { IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n"); /* make request to retrieve statistics information */ - iwl_send_statistics_request(priv, 0); + iwl_send_statistics_request(priv, CMD_SYNC, false); /* Reschedule the ct_kill wait timer */ mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm, jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION)); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 61b3b0e6ed73..9d010a0d83af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -635,6 +635,24 @@ void iwl_rx_statistics(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_rx_statistics); +void iwl_reply_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + + if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { + memset(&priv->statistics, 0, + sizeof(struct iwl_notif_statistics)); +#ifdef CONFIG_IWLWIFI_DEBUG + memset(&priv->accum_statistics, 0, + sizeof(struct iwl_notif_statistics)); +#endif + IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); + } + iwl_rx_statistics(priv, rxb); +} +EXPORT_SYMBOL(iwl_reply_statistics); + #define PERFECT_RSSI (-20) /* dBm */ #define WORST_RSSI (-95) /* dBm */ #define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 05f118529fea..93bb4d341be3 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3649,7 +3649,7 @@ static ssize_t show_statistics(struct device *d, return -EAGAIN; mutex_lock(&priv->mutex); - rc = iwl_send_statistics_request(priv, 0); + rc = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (rc) { -- cgit v1.2.3 From 4d6ccbf57ff7653217b7149976aa31e19f996544 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 13 Nov 2009 11:56:29 -0800 Subject: iwl3945: Reset saved POWER_TABLE_CMD in "up" Power-saving logic will not re-issue a POWER_TABLE_CMD if a new command matches the prior one. This can be bad if we re-start the device due to e.g. uCode error; the new POWER_TABLE_CMD (required to invoke power-saving) may match the prior POWER_TABLE_CMD issued before the uCode error. Ensure the POWER_TABLE_CMD is sent to device when uCode is up. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 93bb4d341be3..31f3c42b835c 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2493,7 +2493,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; - iwl_power_update_mode(priv, false); + iwl_power_update_mode(priv, true); if (iwl_is_associated(priv)) { struct iwl3945_rxon_cmd *active_rxon = -- cgit v1.2.3 From ae16fc3c3184bf27f0462e1951df918122498829 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:30 -0800 Subject: iwlwifi: eliminate the possible 1/2 dBm tx power loss in 6x00 & 6x50 series In both 6x00 and 6x50 series, the enhanced/extended tx power table in EEPROM is used to set the max. tx power limit. This new tx power table is in 1/2 dBm format, which creates an issue of possibility of 1/2 dBm loss when driver set the tx power limit; because of driver keep track and report the tx power in dBm format. In order to prevent the 1/2 dBm loss, keep track of the true max tx power in 1/2 dBm format in driver; do the comparison and adjust the tx power if needed when send tx power command to uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 16 ++++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl-eeprom.c | 49 ++++++++++++++++++++++--------- 3 files changed, 52 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 6eaf26b07636..48982fb44995 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1250,6 +1250,22 @@ int iwl5000_send_tx_power(struct iwl_priv *priv) /* half dBm need to multiply */ tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt); + + if (priv->tx_power_lmt_in_half_dbm && + priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) { + /* + * For the newer devices which using enhanced/extend tx power + * table in EEPROM, the format is in half dBm. driver need to + * convert to dBm format before report to mac80211. + * By doing so, there is a possibility of 1/2 dBm resolution + * lost. driver will perform "round-up" operation before + * reporting, but it will cause 1/2 dBm tx power over the + * regulatory limit. Perform the checking here, if the + * "tx_power_user_lmt" is higher than EEPROM value (in + * half-dBm format), lower the tx power based on EEPROM + */ + tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm; + } tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED; tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 774a315996e6..a474383ec0b8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1247,6 +1247,7 @@ struct iwl_priv { /* TX Power */ s8 tx_power_user_lmt; s8 tx_power_device_lmt; + s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */ #ifdef CONFIG_IWLWIFI_DEBUG diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index e42eb6499f0e..ac88ff042d46 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -762,7 +762,8 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, * 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) + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int element, s8 *max_txpower_in_half_dbm) { s8 max_txpower_avg = 0; /* (dBm) */ @@ -794,10 +795,14 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, (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 + /* + * max. tx power in EEPROM is in 1/2 dBm format + * convert from 1/2 dBm to dBm (round-up convert) + * but we also do not want to loss 1/2 dBm resolution which + * will impact performance */ - return max_txpower_avg >> 1; + *max_txpower_in_half_dbm = max_txpower_avg; + return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1); } /** @@ -806,7 +811,7 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, */ static s8 iwl_update_common_txpower(struct iwl_priv *priv, struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, - int section, int element) + int section, int element, s8 *max_txpower_in_half_dbm) { struct iwl_channel_info *ch_info; int ch; @@ -820,20 +825,22 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv, if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) is_ht40 = true; max_txpower_avg = - iwl_get_max_txpower_avg(priv, enhanced_txpower, element); + iwl_get_max_txpower_avg(priv, enhanced_txpower, + element, max_txpower_in_half_dbm); + 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)) { + (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; + 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; @@ -849,7 +856,7 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv, */ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, - int section, int element) + int section, int element, s8 *max_txpower_in_half_dbm) { struct iwl_channel_info *ch_info; int ch; @@ -858,7 +865,8 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, channel = enhinfo[section].iwl_eeprom_section_channel[element]; max_txpower_avg = - iwl_get_max_txpower_avg(priv, enhanced_txpower, element); + iwl_get_max_txpower_avg(priv, enhanced_txpower, + element, max_txpower_in_half_dbm); ch_info = priv->channel_info; for (ch = 0; ch < priv->channel_count; ch++) { @@ -872,7 +880,6 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, 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; @@ -894,6 +901,7 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; u32 offset; s8 max_txpower_avg; /* (dBm) */ + s8 max_txpower_in_half_dbm; /* (half-dBm) */ /* Loop through all the sections * adjust bands and channel's max tx power @@ -920,16 +928,29 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) if (enhinfo[section].is_common) max_txpower_avg = iwl_update_common_txpower(priv, - enhanced_txpower, section, element); + enhanced_txpower, section, + element, + &max_txpower_in_half_dbm); else max_txpower_avg = iwl_update_channel_txpower(priv, - enhanced_txpower, section, element); + enhanced_txpower, section, + element, + &max_txpower_in_half_dbm); /* 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; + + /* + * Update the tx_power_lmt_in_half_dbm to + * the highest power supported by any channel + */ + if (max_txpower_in_half_dbm > + priv->tx_power_lmt_in_half_dbm) + priv->tx_power_lmt_in_half_dbm = + max_txpower_in_half_dbm; } } } -- cgit v1.2.3 From 98a7b43be19faa7b92576c62614c45e38517331c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:31 -0800 Subject: iwlwifi: align tx/rx statistics debugfs format Align the format for tx_statistics and rx_statistics debugfs output for better readability Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 45a5edd1b1a7..ba9c96ff27ca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -131,21 +131,22 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, int cnt; ssize_t ret; - const size_t bufsz = 100 + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); + const size_t bufsz = 100 + + sizeof(char) * 50 * (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", + "\t%25s\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", + "\t%25s\t\t: %u\n", get_ctrl_string(cnt), priv->tx_stats.ctrl[cnt]); } @@ -190,7 +191,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, int cnt; ssize_t ret; const size_t bufsz = 100 + - sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); + sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX); buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -198,14 +199,14 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, 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", + "\t%25s\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", + "\t%25s\t\t: %u\n", get_ctrl_string(cnt), priv->rx_stats.ctrl[cnt]); } -- cgit v1.2.3 From e43ab94d2ea01a74e60c3423334687c2156c39b2 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 13 Nov 2009 11:56:32 -0800 Subject: iwlagn: power up device before initializing EEPROM A recent change optimized the power usage by the device by only powering it up during EEPROM load if it is required (for OTP devices). This change causes an error on the 1000 series devices during module load. The error looks as follows: [ 1624.024524] iwlagn: Intel(R) Wireless WiFi Link AGN driver for Linux, 1.3.27kds [ 1624.024527] iwlagn: Copyright(c) 2003-2009 Intel Corporation [ 1624.024711] iwlagn 0000:01:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16 [ 1624.024749] iwlagn 0000:01:00.0: setting latency timer to 64 [ 1624.024909] iwlagn 0000:01:00.0: Detected Intel Wireless WiFi Link 1000 Series BGN REV=0x6C [ 1624.081263] iwlagn 0000:01:00.0: MAC is in deep sleep!. CSR_GP_CNTRL = 0x080003D8 [ 1624.092967] iwlagn 0000:01:00.0: OTP is empty [ 1624.092988] iwlagn 0000:01:00.0: Unable to init EEPROM [ 1624.093033] iwlagn 0000:01:00.0: PCI INT A disabled [ 1624.093065] iwlagn: probe of 0000:01:00.0 failed with error -2 Adding a dump_stack() to where that error is printed shows the following: [ 1624.024524] iwlagn: Intel(R) Wireless WiFi Link AGN driver for Linux, 1.3.27kds [ 1624.024527] iwlagn: Copyright(c) 2003-2009 Intel Corporation [ 1624.024711] iwlagn 0000:01:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16 [ 1624.024749] iwlagn 0000:01:00.0: setting latency timer to 64 [ 1624.024909] iwlagn 0000:01:00.0: Detected Intel Wireless WiFi Link 1000 Series BGN REV=0x6C [ 1624.081263] iwlagn 0000:01:00.0: MAC is in deep sleep!. CSR_GP_CNTRL = 0x080003D8 [ 1624.081263] Pid: 3073, comm: work_for_cpu Tainted: G W 2.6.31.5 #4 [ 1624.081263] Call Trace: [ 1624.081263] [] T.726+0x22b/0x420 [iwlcore] [ 1624.081263] [] iwlcore_eeprom_acquire_semaphore+0x8a/0x190 [iwlcore] [ 1624.081263] [] ? __kmalloc+0x194/0x1c0 [ 1624.081263] [] ? iwlcore_eeprom_verify_signature+0x25/0xf0 [iwlcore] [ 1624.081263] [] iwl_eeprom_init+0x107/0xf40 [iwlcore] [ 1624.081263] [] ? iwl_prepare_card_hw+0x11c/0x470 [iwlagn] [ 1624.081263] [] ? pci_bus_write_config_byte+0x64/0x80 [ 1624.081263] [] iwl_pci_probe+0x308/0xac0 [iwlagn] [ 1624.081263] [] ? do_work_for_cpu+0x0/0x30 [ 1624.081263] [] local_pci_probe+0x12/0x20 [ 1624.081263] [] do_work_for_cpu+0x13/0x30 [ 1624.081263] [] kthread+0xa6/0xb0 [ 1624.081263] [] child_rip+0xa/0x20 [ 1624.081263] [] ? kthread+0x0/0xb0 [ 1624.081263] [] ? child_rip+0x0/0x20 [ 1624.092967] iwlagn 0000:01:00.0: OTP is empty [ 1624.092988] iwlagn 0000:01:00.0: Unable to init EEPROM [ 1624.093033] iwlagn 0000:01:00.0: PCI INT A disabled [ 1624.093065] iwlagn: probe of 0000:01:00.0 failed with error -2 We know that the routines in this trace, iwlcore_eeprom_acquire_semaphore and iwlcore_eeprom_verify_signature, only access CSR registers and thus do not need the device to be awake if it is EEPROM. But for OTP it is required for the device to be awake to read these registers. Ensure device is awake before accessing these registers. Signed-off-by: Reinette Chatre Acked-by: Ben Cahill Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index ac88ff042d46..3946e5c03f81 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -518,6 +518,11 @@ int iwl_eeprom_init(struct iwl_priv *priv) } e = (u16 *)priv->eeprom; + if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { + /* OTP reads require powered-up chip */ + priv->cfg->ops->lib->apm_ops.init(priv); + } + ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv); if (ret < 0) { IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); @@ -532,10 +537,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) ret = -ENOENT; goto err; } - if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { - /* OTP reads require powered-up chip */ - priv->cfg->ops->lib->apm_ops.init(priv); + if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { ret = iwl_init_otp_access(priv); if (ret) { -- cgit v1.2.3 From 47ff65c48748086a5e9cde6032451691a28ab19f Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 13 Nov 2009 11:56:33 -0800 Subject: iwlwifi: fix bugs in beacon configuration When sending beacon commands to the uCode, we must inform it of the offset in the beacon frame of the TIM Element so it can transmit packets from the correct queue. This functionality is implemented in iwl_set_beacon_tim(). Fix a bug setting the rate_n_flags for the beacon packet. First, it should not use the station table's rate (it's a management frame), and second it needs to properly configure the TX antennas. Finally, also, clean up and comment relevant functions. Signed-off-by: Daniel C Halperin Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 83 ++++++++++++++++++++++++--------- drivers/net/wireless/iwlwifi/iwl-core.c | 1 + 2 files changed, 63 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f586e7e83131..29f3b73c7560 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -310,7 +310,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) list_add(&frame->list, &priv->free_frames); } -static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, +static u32 iwl_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, int left) { @@ -327,34 +327,74 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, return priv->ibss_beacon->len; } +/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */ +static void iwl_set_beacon_tim(struct iwl_priv *priv, + struct iwl_tx_beacon_cmd *tx_beacon_cmd, + u8 *beacon, u32 frame_size) +{ + u16 tim_idx; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon; + + /* + * The index is relative to frame start but we start looking at the + * variable-length part of the beacon. + */ + tim_idx = mgmt->u.beacon.variable - beacon; + + /* Parse variable-length elements of beacon to find WLAN_EID_TIM */ + while ((tim_idx < (frame_size - 2)) && + (beacon[tim_idx] != WLAN_EID_TIM)) + tim_idx += beacon[tim_idx+1] + 2; + + /* If TIM field was found, set variables */ + if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) { + tx_beacon_cmd->tim_idx = cpu_to_le16(tim_idx); + tx_beacon_cmd->tim_size = beacon[tim_idx+1]; + } else + IWL_WARN(priv, "Unable to find TIM Element in beacon\n"); +} + static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame, u8 rate) + struct iwl_frame *frame) { struct iwl_tx_beacon_cmd *tx_beacon_cmd; - unsigned int frame_size; + u32 frame_size; + u32 rate_flags; + u32 rate; + /* + * We have to set up the TX command, the TX Beacon command, and the + * beacon contents. + */ + /* Initialize memory */ tx_beacon_cmd = &frame->u.beacon; memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); - tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id; - tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - + /* Set up TX beacon contents */ frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); + if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE)) + return 0; - BUG_ON(frame_size > MAX_MPDU_SIZE); + /* Set up TX command fields */ tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); + tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id; + tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK | + TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK; - if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) - tx_beacon_cmd->tx.rate_n_flags = - iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); - else - tx_beacon_cmd->tx.rate_n_flags = - iwl_hw_set_rate_n_flags(rate, 0); + /* Set up TX beacon command fields */ + iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame, + frame_size); - tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK | - TX_CMD_FLG_TSF_MSK | - TX_CMD_FLG_STA_RATE_MSK; + /* Set up packet rate and flags */ + rate = iwl_rate_get_lowest_plcp(priv); + 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 ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE)) + rate_flags |= RATE_MCS_CCK_MSK; + tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, + rate_flags); return sizeof(*tx_beacon_cmd) + frame_size; } @@ -363,19 +403,20 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv) struct iwl_frame *frame; unsigned int frame_size; int rc; - u8 rate; frame = iwl_get_free_frame(priv); - if (!frame) { IWL_ERR(priv, "Could not obtain free frame buffer for beacon " "command.\n"); return -ENOMEM; } - rate = iwl_rate_get_lowest_plcp(priv); - - frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); + frame_size = iwl_hw_get_beacon_cmd(priv, frame); + if (!frame_size) { + IWL_ERR(priv, "Error configuring the beacon command\n"); + iwl_free_frame(priv, frame); + return -EINVAL; + } rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1736c60c3e21..33da44f96e9f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -208,6 +208,7 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant) } return ant; } +EXPORT_SYMBOL(iwl_toggle_tx_ant); const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; EXPORT_SYMBOL(iwl_bcast_addr); -- cgit v1.2.3 From f513dfff9622ac72c461770e1fa01d291ba6ba5a Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 13 Nov 2009 11:56:34 -0800 Subject: iwlwifi: make iwlwifi send beacons Handle BSS_CHANGED_BEACON_ENABLED to enable the sending of beacons. Also set the correct HT RXON and QoS config. Signed-off-by: Daniel C Halperin Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl-core.c | 8 ++++++++ 2 files changed, 13 insertions(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 29f3b73c7560..1c6506529b6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2563,6 +2563,10 @@ void iwl_config_ap(struct iwl_priv *priv) IWL_WARN(priv, "REPLY_RXON_TIMING failed - " "Attempting to continue.\n"); + /* AP has all antennas */ + priv->chain_noise_data.active_chains = + priv->hw_params.valid_rx_ant; + iwl_set_rxon_ht(priv, &priv->current_ht_config); if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv); @@ -2591,6 +2595,7 @@ void iwl_config_ap(struct iwl_priv *priv) /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv); + iwl_reset_qos(priv); spin_lock_irqsave(&priv->lock, flags); iwl_activate_qos(priv, 1); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 33da44f96e9f..a2636f4b068f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2497,6 +2497,14 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, } } + if ((changes & BSS_CHANGED_BEACON_ENABLED) && + vif->bss_conf.enable_beacon) { + memcpy(priv->staging_rxon.bssid_addr, + bss_conf->bssid, ETH_ALEN); + memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); + iwlcore_config_ap(priv); + } + mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); -- cgit v1.2.3 From c397bf15a6067ecf39f8a771907f4721a64fd61f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 13 Nov 2009 11:56:35 -0800 Subject: iwlwifi: report PS filtered status When a frame is sent to a sleeping station, the microcode reports TX_STATUS_FAIL_DEST_PS as its status -- we need to translate that to the flag that mac80211 expects. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 6 ++---- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 ++---- drivers/net/wireless/iwlwifi/iwl-commands.h | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1d22ea390c00..0efde87b4597 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1864,8 +1864,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_is_tx_success(status) ? - IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_tx_status_to_mac80211(status); iwl_hwrate_to_tx_control(priv, rate_n_flags, info); /* FIXME: code repetition end */ @@ -2020,8 +2019,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, } } else { info->status.rates[0].count = tx_resp->failure_frame + 1; - info->flags |= iwl_is_tx_success(status) ? - IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_tx_status_to_mac80211(status); iwl_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 48982fb44995..570eaa08531f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -993,8 +993,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_is_tx_success(status) ? - IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_tx_status_to_mac80211(status); iwl_hwrate_to_tx_control(priv, rate_n_flags, info); /* FIXME: code repetition end */ @@ -1139,8 +1138,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, BUG_ON(txq_id != txq->swq_id); info->status.rates[0].count = tx_resp->failure_frame + 1; - info->flags |= iwl_is_tx_success(status) ? - IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_tx_status_to_mac80211(status); iwl_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6e23a2b5cb8a..87a7f2832c53 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1690,6 +1690,21 @@ enum { TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ }; +static inline u32 iwl_tx_status_to_mac80211(u32 status) +{ + status &= TX_STATUS_MSK; + + switch (status) { + case TX_STATUS_SUCCESS: + case TX_STATUS_DIRECT_DONE: + return IEEE80211_TX_STAT_ACK; + case TX_STATUS_FAIL_DEST_PS: + return IEEE80211_TX_STAT_TX_FILTERED; + default: + return 0; + } +} + static inline bool iwl_is_tx_success(u32 status) { status &= TX_STATUS_MSK; -- cgit v1.2.3 From 9bb487b406692e172b15eba58de7d69358ac2005 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 13 Nov 2009 11:56:36 -0800 Subject: iwlwifi: add sleep_tx_count ucode station API This field was marked as reserved before since we didn't use it, but is present in all released firmwares afaict. We're going to need it soon, so add it now. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-commands.h | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 0efde87b4597..1e58c49dd768 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1817,6 +1817,7 @@ static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid; addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid; addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn; + addsta->sleep_tx_count = cmd->sleep_tx_count; addsta->reserved1 = cpu_to_le16(0); addsta->reserved2 = cpu_to_le32(0); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 87a7f2832c53..aa4e38cbf071 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1107,7 +1107,14 @@ struct iwl4965_addsta_cmd { * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ __le16 add_immediate_ba_ssn; - __le32 reserved2; + /* + * Number of packets OK to transmit to station even though + * it is asleep -- used to synchronise PS-poll and u-APSD + * responses while ucode keeps track of STA sleep state. + */ + __le16 sleep_tx_count; + + __le16 reserved2; } __attribute__ ((packed)); /* 5000 */ @@ -1138,7 +1145,14 @@ struct iwl_addsta_cmd { * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ __le16 add_immediate_ba_ssn; - __le32 reserved2; + /* + * Number of packets OK to transmit to station even though + * it is asleep -- used to synchronise PS-poll and u-APSD + * responses while ucode keeps track of STA sleep state. + */ + __le16 sleep_tx_count; + + __le16 reserved2; } __attribute__ ((packed)); -- cgit v1.2.3 From 6ab10ff8738dfb098fd32132b7ebcf5cdb43ebde Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 13 Nov 2009 11:56:37 -0800 Subject: iwlwifi: handle unicast PS buffering Using the new mac80211 functionality, this makes iwlwifi handle unicast PS buffering correctly. The device works like this: * when a station goes to sleep, the microcode notices this and marks the station as asleep * when the station is marked asleep, the microcode refuses to transmit to the station and rejects all frames queued to it with the failure status code TX_STATUS_FAIL_DEST_PS (a previous patch handled this correctly) * when we need to send frames to the station _although_ it is asleep, we need to tell the ucode how many, and this is asynchronous with sending so we cannot just send the frames, we need to wait for all other frames to be flushed, and then update the counter before sending out the poll response frames. This is handled partially in the driver and partially in mac80211. In order to do all this correctly, we need to * keep track of how many frames are pending for each associated client station (avoid doing it for other stations to avoid the atomic ops) * tell mac80211 that we driver-block the PS status while there are still frames pending on the queues, and once they are all rejected (due to the dest sta being in PS) unblock mac80211 Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 42 +++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-commands.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 -- drivers/net/wireless/iwlwifi/iwl-dev.h | 10 ++---- drivers/net/wireless/iwlwifi/iwl-rx.c | 17 ++-------- drivers/net/wireless/iwlwifi/iwl-sta.c | 29 ++++++++-------- drivers/net/wireless/iwlwifi/iwl-sta.h | 3 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 51 ++++++++++++++++++++++++++++- 8 files changed, 113 insertions(+), 42 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1c6506529b6e..6385cdf24d13 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2744,6 +2744,45 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, return 0; } +static void iwl_mac_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; + int sta_id; + + /* + * TODO: We really should use this callback to + * actually maintain the station table in + * the device. + */ + + switch (cmd) { + case STA_NOTIFY_ADD: + atomic_set(&sta_priv->pending_frames, 0); + if (vif->type == NL80211_IFTYPE_AP) + sta_priv->client = true; + break; + case STA_NOTIFY_SLEEP: + WARN_ON(!sta_priv->client); + sta_priv->asleep = true; + if (atomic_read(&sta_priv->pending_frames) > 0) + ieee80211_sta_block_awake(hw, sta, true); + break; + case STA_NOTIFY_AWAKE: + WARN_ON(!sta_priv->client); + sta_priv->asleep = false; + sta_id = iwl_find_station(priv, sta->addr); + if (sta_id != IWL_INVALID_STATION) + iwl_sta_modify_ps_wake(priv, sta_id); + break; + default: + break; + } +} + /***************************************************************************** * * sysfs attributes @@ -3175,7 +3214,8 @@ static struct ieee80211_ops iwl_hw_ops = { .reset_tsf = iwl_mac_reset_tsf, .bss_info_changed = iwl_bss_info_changed, .ampdu_action = iwl_mac_ampdu_action, - .hw_scan = iwl_mac_hw_scan + .hw_scan = iwl_mac_hw_scan, + .sta_notify = iwl_mac_sta_notify, }; static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index aa4e38cbf071..e91507531923 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -977,6 +977,7 @@ struct iwl_qosparam_cmd { #define STA_MODIFY_TX_RATE_MSK 0x04 #define STA_MODIFY_ADDBA_TID_MSK 0x08 #define STA_MODIFY_DELBA_TID_MSK 0x10 +#define STA_MODIFY_SLEEP_TX_COUNT_MSK 0x20 /* Receiver address (actually, Rx station's index into station table), * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index ba9c96ff27ca..9a5ca25d72c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -336,8 +336,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, pos += scnprintf(buf + pos, bufsz - pos, "flags: 0x%x\n", station->sta.station_flags_msk); - pos += scnprintf(buf + pos, bufsz - pos, - "ps_status: %u\n", station->ps_status); pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n"); pos += scnprintf(buf + pos, bufsz - pos, "seq_num\t\ttxq_id"); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index a474383ec0b8..f1601cfebc29 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -545,15 +545,11 @@ struct iwl_qos_info { struct iwl_qosparam_cmd def_qos_parm; }; -#define STA_PS_STATUS_WAKE 0 -#define STA_PS_STATUS_SLEEP 1 - struct iwl3945_station_entry { struct iwl3945_addsta_cmd sta; struct iwl_tid_data tid[MAX_TID_COUNT]; u8 used; - u8 ps_status; struct iwl_hw_key keyinfo; }; @@ -561,7 +557,6 @@ struct iwl_station_entry { struct iwl_addsta_cmd sta; struct iwl_tid_data tid[MAX_TID_COUNT]; u8 used; - u8 ps_status; struct iwl_hw_key keyinfo; }; @@ -571,11 +566,12 @@ struct iwl_station_entry { * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is places in that * space. - * - * At the moment use it for the station's rate scaling information. */ struct iwl_station_priv { struct iwl_lq_sta lq_sta; + atomic_t pending_frames; + bool client; + bool asleep; }; /* one for each uCode image (inst/data, boot/init/runtime) */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 9d010a0d83af..cc980d5d57c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1028,7 +1028,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, struct iwl4965_rx_mpdu_res_start *amsdu; u32 len; u32 ampdu_status; - u16 fc; u32 rate_n_flags; /** @@ -1161,20 +1160,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, priv->last_tsf = le64_to_cpu(phy_res->timestamp); } - fc = le16_to_cpu(header->frame_control); - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_MGMT: - case IEEE80211_FTYPE_DATA: - if (priv->iw_mode == NL80211_IFTYPE_AP) - iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, - header->addr2); - /* fall through */ - default: - iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, - rxb, &rx_status); - break; - - } + iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, + rxb, &rx_status); } EXPORT_SYMBOL(iwl_rx_reply_rx); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index eba36f737388..cd6a6901216e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1216,7 +1216,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) } EXPORT_SYMBOL(iwl_sta_rx_agg_stop); -static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) { unsigned long flags; @@ -1224,27 +1224,26 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.sleep_tx_count = 0; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } +EXPORT_SYMBOL(iwl_sta_modify_ps_wake); -void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) +void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) { - /* FIXME: need locking over ps_status ??? */ - u8 sta_id = iwl_find_station(priv, addr); + unsigned long flags; - if (sta_id != IWL_INVALID_STATION) { - u8 sta_awake = priv->stations[sta_id]. - ps_status == STA_PS_STATUS_WAKE; + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = + STA_MODIFY_SLEEP_TX_COUNT_MSK; + priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); - if (sta_awake && ps_bit) - priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; - else if (!sta_awake && !ps_bit) { - iwl_sta_modify_ps_wake(priv, sta_id); - priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; - } - } + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } - diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 1c382de80d49..8d052de2d405 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -66,5 +66,6 @@ void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); int iwl_sta_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn); int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); -void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr); +void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id); +void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt); #endif /* __iwl_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9370e062000d..ebfc460115d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -709,6 +709,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->control.sta; + struct iwl_station_priv *sta_priv = NULL; struct iwl_tx_queue *txq; struct iwl_queue *q; struct iwl_device_cmd *out_cmd; @@ -771,6 +773,24 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); + if (sta) + sta_priv = (void *)sta->drv_priv; + + if (sta_priv && sta_id != priv->hw_params.bcast_sta_id && + sta_priv->asleep) { + WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)); + /* + * This sends an asynchronous command to the device, + * but we can rely on it being processed before the + * next frame is processed -- and the next frame to + * this station is the one that will consume this + * counter. + * For now set the counter to just 1 since we do not + * support uAPSD yet. + */ + iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); + } + txq_id = skb_get_queue_mapping(skb); if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); @@ -930,6 +950,17 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) ret = iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); + /* + * At this point the frame is "transmitted" successfully + * and we will get a TX status notification eventually, + * regardless of the value of ret. "ret" only indicates + * whether or not we should update the write pointer. + */ + + /* avoid atomic ops if it isn't an associated client */ + if (sta_priv && sta_priv->client) + atomic_inc(&sta_priv->pending_frames); + if (ret) return ret; @@ -1074,6 +1105,24 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return ret ? ret : idx; } +static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_sta *sta; + struct iwl_station_priv *sta_priv; + + sta = ieee80211_find_sta(priv->vif, hdr->addr1); + if (sta) { + sta_priv = (void *)sta->drv_priv; + /* avoid atomic ops if this isn't a client */ + if (sta_priv->client && + atomic_dec_return(&sta_priv->pending_frames) == 0) + ieee80211_sta_block_awake(priv->hw, sta, false); + } + + ieee80211_tx_status_irqsafe(priv->hw, skb); +} + int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) { struct iwl_tx_queue *txq = &priv->txq[txq_id]; @@ -1093,7 +1142,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); + iwl_tx_status(priv, tx_info->skb[0]); tx_info->skb[0] = NULL; if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) -- cgit v1.2.3 From 9e595d24b13a021ead42bedd5edba8801b0da6cd Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 13 Nov 2009 11:56:38 -0800 Subject: iwlwifi: Add comments about CSR registers Also regroup CSR_EEPROM and CSR_OTP bit field definitions. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-csr.h | 177 ++++++++++++++++++++++++++++----- 1 file changed, 150 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index b6ed5a3147a1..68ed82206723 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -62,11 +62,29 @@ *****************************************************************************/ #ifndef __iwl_csr_h__ #define __iwl_csr_h__ -/*=== CSR (control and status registers) ===*/ +/* + * CSR (control and status registers) + * + * CSR registers are mapped directly into PCI bus space, and are accessible + * whenever platform supplies power to device, even when device is in + * low power states due to driver-invoked device resets + * (e.g. CSR_RESET_REG_FLAG_SW_RESET) or uCode-driven power-saving modes. + * + * Use iwl_write32() and iwl_read32() family to access these registers; + * these provide simple PCI bus access, without waking up the MAC. + * Do not use iwl_write_direct32() family for these registers; + * no need to "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ. + * The MAC (uCode processor, etc.) does not need to be powered up for accessing + * the CSR registers. + * + * NOTE: Newer devices using one-time-programmable (OTP) memory + * require device to be awake in order to read this memory + * via CSR_EEPROM and CSR_OTP registers + */ #define CSR_BASE (0x000) #define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ -#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ +#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ #define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ #define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ #define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ @@ -74,42 +92,65 @@ #define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ #define CSR_GP_CNTRL (CSR_BASE+0x024) +/* 2nd byte of CSR_INT_COALESCING, not accessible via iwl_write32()! */ +#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005) + /* * Hardware revision info * Bit fields: * 31-8: Reserved - * 7-4: Type of device: 0x0 = 4965, 0xd = 3945 + * 7-4: Type of device: see CSR_HW_REV_TYPE_xxx definitions * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D - * 1-0: "Dash" value, as in A-1, etc. + * 1-0: "Dash" (-) value, as in A-1, etc. * * NOTE: Revision step affects calculation of CCK txpower for 4965. + * NOTE: See also CSR_HW_REV_WA_REG (work-around for bug in 4965). */ #define CSR_HW_REV (CSR_BASE+0x028) -/* EEPROM reads */ +/* + * EEPROM and OTP (one-time-programmable) memory reads + * + * NOTE: For (newer) devices using OTP, device must be awake, initialized via + * apm_ops.init() in order to read. Older devices (3945/4965/5000) + * use EEPROM and do not require this. + */ #define CSR_EEPROM_REG (CSR_BASE+0x02c) #define CSR_EEPROM_GP (CSR_BASE+0x030) #define CSR_OTP_GP_REG (CSR_BASE+0x034) + #define CSR_GIO_REG (CSR_BASE+0x03C) #define CSR_GP_UCODE_REG (CSR_BASE+0x048) #define CSR_GP_DRIVER_REG (CSR_BASE+0x050) + +/* + * UCODE-DRIVER GP (general purpose) mailbox registers. + * SET/CLR registers set/clear bit(s) if "1" is written. + */ #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) #define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) + #define CSR_LED_REG (CSR_BASE+0x094) #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) + +/* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) -#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005) /* Analog phase-lock-loop configuration */ #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) + /* - * Indicates hardware rev, to determine CCK backoff for txpower calculation. + * CSR Hardware Revision Workaround Register. Indicates hardware rev; + * "step" determines CCK backoff for txpower calculation. Used for 4965 only. + * See also CSR_HW_REV register. * Bit fields: * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step + * 1-0: "Dash" (-) value, as in C-1, etc. */ #define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) + #define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240) #define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250) @@ -126,11 +167,11 @@ #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) -#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) -#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) -#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) -#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) -#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) +#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) +#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) +#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ +#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ +#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ #define CSR_INT_PERIODIC_DIS (0x00) #define CSR_INT_PERIODIC_ENA (0xFF) @@ -198,7 +239,44 @@ #define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) #define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000) -/* GP (general purpose) CONTROL */ +/* + * GP (general purpose) CONTROL REGISTER + * Bit fields: + * 27: HW_RF_KILL_SW + * Indicates state of (platform's) hardware RF-Kill switch + * 26-24: POWER_SAVE_TYPE + * Indicates current power-saving mode: + * 000 -- No power saving + * 001 -- MAC power-down + * 010 -- PHY (radio) power-down + * 011 -- Error + * 9-6: SYS_CONFIG + * Indicates current system configuration, reflecting pins on chip + * as forced high/low by device circuit board. + * 4: GOING_TO_SLEEP + * Indicates MAC is entering a power-saving sleep power-down. + * Not a good time to access device-internal resources. + * 3: MAC_ACCESS_REQ + * Host sets this to request and maintain MAC wakeup, to allow host + * access to device-internal resources. Host must wait for + * MAC_CLOCK_READY (and !GOING_TO_SLEEP) before accessing non-CSR + * device registers. + * 2: INIT_DONE + * Host sets this to put device into fully operational D0 power mode. + * Host resets this after SW_RESET to put device into low power mode. + * 0: MAC_CLOCK_READY + * Indicates MAC (ucode processor, etc.) is powered up and can run. + * Internal resources are accessible. + * NOTE: This does not indicate that the processor is actually running. + * NOTE: This does not indicate that 4965 or 3945 has completed + * init or post-power-down restore of internal SRAM memory. + * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that + * SRAM is restored and uCode is in normal operation mode. + * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and + * do not need to save/restore it. + * NOTE: After device reset, this bit remains "0" until host sets + * INIT_DONE + */ #define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) #define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) #define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) @@ -231,28 +309,58 @@ #define CSR_EEPROM_REG_MSK_DATA (0xFFFF0000) /* EEPROM GP */ -#define CSR_EEPROM_GP_VALID_MSK (0x00000007) +#define CSR_EEPROM_GP_VALID_MSK (0x00000007) /* signature */ #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) +#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000) +#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001) +#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002) +#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004) + +/* One-time-programmable memory general purpose reg */ #define CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */ #define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ #define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ #define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ + +/* GP REG */ #define CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */ #define CSR_GP_REG_NO_POWER_SAVE (0x00000000) #define CSR_GP_REG_MAC_POWER_SAVE (0x01000000) #define CSR_GP_REG_PHY_POWER_SAVE (0x02000000) #define CSR_GP_REG_POWER_SAVE_ERROR (0x03000000) -/* EEPROM signature */ -#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000) -#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001) -#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002) -#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004) /* CSR GIO */ #define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002) -/* UCODE DRV GP */ +/* + * UCODE-DRIVER GP (general purpose) mailbox register 1 + * Host driver and uCode write and/or read this register to communicate with + * each other. + * Bit fields: + * 4: UCODE_DISABLE + * Host sets this to request permanent halt of uCode, same as + * sending CARD_STATE command with "halt" bit set. + * 3: CT_KILL_EXIT + * Host sets this to request exit from CT_KILL state, i.e. host thinks + * device temperature is low enough to continue normal operation. + * 2: CMD_BLOCKED + * Host sets this during RF KILL power-down sequence (HW, SW, CT KILL) + * to release uCode to clear all Tx and command queues, enter + * unassociated mode, and power down. + * NOTE: Some devices also use HBUS_TARG_MBX_C register for this bit. + * 1: SW_BIT_RFKILL + * Host sets this when issuing CARD_STATE command to request + * device sleep. + * 0: MAC_SLEEP + * uCode sets this when preparing a power-saving power-down. + * uCode resets this when power-up is complete and SRAM is sane. + * NOTE: 3945/4965 saves internal SRAM data to host when powering down, + * and must restore this data after powering back up. + * MAC_SLEEP is the best indication that restore is complete. + * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and + * do not need to save/restore it. + */ #define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) #define CSR_UCODE_SW_BIT_RFKILL (0x00000002) #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) @@ -265,7 +373,7 @@ #define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002) -/* GI Chicken Bits */ +/* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) @@ -285,8 +393,23 @@ #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) -/*=== HBUS (Host-side Bus) ===*/ +/* + * HBUS (Host-side Bus) + * + * HBUS registers are mapped directly into PCI bus space, but are used + * to indirectly access device's internal memory or registers that + * may be powered-down. + * + * Use iwl_write_direct32()/iwl_read_direct32() family for these registers; + * host must "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ + * to make sure the MAC (uCode processor, etc.) is powered up for accessing + * internal resources. + * + * Do not use iwl_write32()/iwl_read32() family to access these registers; + * these provide only simple PCI bus access, without waking up the MAC. + */ #define HBUS_BASE (0x400) + /* * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM * structures, error log, event log, verifying uCode load). @@ -301,6 +424,10 @@ #define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) #define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) +/* Mailbox C, used as workaround alternative to CSR_UCODE_DRV_GP1 mailbox */ +#define HBUS_TARG_MBX_C (HBUS_BASE+0x030) +#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) + /* * Registers for accessing device's internal peripheral registers * (e.g. SCD, BSM, etc.). First write to address register, @@ -315,16 +442,12 @@ #define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) /* - * Per-Tx-queue write pointer (index, really!) (3945 and 4965). + * Per-Tx-queue write pointer (index, really!) * Indicates index to next TFD that driver will fill (1 past latest filled). * Bit usage: * 0-7: queue write index * 11-8: queue selector */ #define HBUS_TARG_WRPTR (HBUS_BASE+0x060) -#define HBUS_TARG_MBX_C (HBUS_BASE+0x030) - -#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) - #endif /* !__iwl_csr_h__ */ -- cgit v1.2.3 From c951ad3550ab40071bb0f222ba6125845769c08a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 16 Nov 2009 12:00:38 +0100 Subject: mac80211: convert aggregation to operate on vifs/stas The entire aggregation code currently operates on the hw pointer and station addresses, but that needs to change to make stations purely per-vif; As one step preparing for that make the aggregation code callable with the station, or by the combination of virtual interface and station address. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/main.c | 5 +- drivers/net/wireless/ath/ath9k/main.c | 5 +- drivers/net/wireless/ath/ath9k/rc.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 1 + drivers/net/wireless/iwlwifi/iwl-tx.c | 8 +-- include/net/mac80211.h | 28 +++++---- net/mac80211/agg-rx.c | 6 +- net/mac80211/agg-tx.c | 96 ++++++++++++------------------- net/mac80211/driver-ops.h | 5 +- net/mac80211/driver-trace.h | 9 ++- net/mac80211/ht.c | 3 +- net/mac80211/ieee80211_i.h | 3 +- net/mac80211/main.c | 8 +-- 14 files changed, 84 insertions(+), 97 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index bd2a276c870a..f9d6db8d013e 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2441,6 +2441,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, } static int ar9170_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { @@ -2470,7 +2471,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw, tid_info->state = AR9170_TID_STATE_PROGRESS; tid_info->active = false; spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: @@ -2480,7 +2481,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw, tid_info->active = false; skb_queue_purge(&tid_info->queue); spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3229c3993568..16bdb1b549b4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -3078,6 +3078,7 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw) } static int ath9k_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) @@ -3095,11 +3096,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, break; case IEEE80211_AMPDU_TX_START: ath_tx_aggr_start(sc, sta, tid, ssn); - ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: ath_tx_aggr_stop(sc, sta, tid); - ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: ath_tx_aggr_resume(sc, sta, tid); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index ea4b9081b4d0..1d96777b4cd2 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1353,7 +1353,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, an = (struct ath_node *)sta->drv_priv; if(ath_tx_aggr_check(sc, an, tid)) - ieee80211_start_tx_ba_session(sc->hw, hdr->addr1, tid); + ieee80211_start_tx_ba_session(sta, tid); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 43edd8fd4405..2f09e3b7f0eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -301,7 +301,7 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n", sta->addr, tid); - ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); + ieee80211_start_tx_ba_session(sta, tid); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6385cdf24d13..b80cd0bc5845 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2691,6 +2691,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index ebfc460115d6..f3dff2ecc406 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1312,7 +1312,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) if (tid_data->tfds_in_queue == 0) { IWL_DEBUG_HT(priv, "HW queue is empty\n"); tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid); + ieee80211_start_tx_ba_cb_irqsafe(priv->vif, ra, tid); } else { IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n", tid_data->tfds_in_queue); @@ -1377,7 +1377,7 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) if (ret) return ret; - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid); + ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid); return 0; } @@ -1401,7 +1401,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, tx_fifo); tid_data->agg.state = IWL_AGG_OFF; - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid); + ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid); } break; case IWL_EMPTYING_HW_QUEUE_ADDBA: @@ -1409,7 +1409,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) if (tid_data->tfds_in_queue == 0) { IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n"); tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid); + ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid); } break; } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3b3defbe6fc1..4af0ffb98aaf 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1508,6 +1508,7 @@ struct ieee80211_ops { void (*reset_tsf)(struct ieee80211_hw *hw); int (*tx_last_beacon)(struct ieee80211_hw *hw); int (*ampdu_action)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn); @@ -2029,8 +2030,7 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, /** * ieee80211_start_tx_ba_session - Start a tx Block Ack session. - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @ra: receiver address of the BA session recipient + * @sta: the station for which to start a BA session * @tid: the TID to BA on. * * Return: success if addBA request was sent, failure otherwise @@ -2039,22 +2039,22 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, * the need to start aggregation on a certain RA/TID, the session level * will be managed by the mac80211. */ -int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid); +int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid); /** * ieee80211_start_tx_ba_cb - low level driver ready to aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the TID to BA on. * * This function must be called by low level driver once it has * finished with preparations for the BA session. */ -void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid); +void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); /** * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the TID to BA on. * @@ -2062,13 +2062,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid); * finished with preparations for the BA session. * This version of the function is IRQ-safe. */ -void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid); /** * ieee80211_stop_tx_ba_session - Stop a Block Ack session. - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @ra: receiver address of the BA session recipient + * @sta: the station whose BA session to stop * @tid: the TID to stop BA. * @initiator: if indicates initiator DELBA frame will be sent. * @@ -2078,24 +2077,23 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, * the need to stop aggregation on a certain RA/TID, the session level * will be managed by the mac80211. */ -int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, - u8 *ra, u16 tid, +int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid, enum ieee80211_back_parties initiator); /** * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the desired TID to BA on. * * This function must be called by low level driver once it has * finished with preparations for the BA session tear down. */ -void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); +void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); /** * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the desired TID to BA on. * @@ -2103,7 +2101,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); * finished with preparations for the BA session tear down. * This version of the function is IRQ-safe. */ -void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid); /** diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index bc064d7933ff..f3a5c9e0578d 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -41,7 +41,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, sta->sta.addr, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - if (drv_ampdu_action(local, IEEE80211_AMPDU_RX_STOP, + if (drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_RX_STOP, &sta->sta, tid, NULL)) printk(KERN_DEBUG "HW problem - can not stop rx " "aggregation for tid %d\n", tid); @@ -284,7 +285,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, goto end; } - ret = drv_ampdu_action(local, IEEE80211_AMPDU_RX_START, + ret = drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_RX_START, &sta->sta, tid, &start_seq_num); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index b09948ceec4a..6ddd11466df2 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -138,7 +138,8 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, *state = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_STOP, + ret = drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_TX_STOP, &sta->sta, tid, NULL); /* HW shall not deny going back to legacy */ @@ -196,11 +197,11 @@ static inline int ieee80211_ac_from_tid(int tid) return ieee802_1d_to_ac[tid & 7]; } -int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) +int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata; + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; u8 *state; int ret = 0; u16 start_seq_num; @@ -208,52 +209,37 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) if (WARN_ON(!local->ops->ampdu_action)) return -EINVAL; - if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) + if ((tid >= STA_TID_NUM) || + !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) return -EINVAL; #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n", - ra, tid); + pubsta->addr, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - rcu_read_lock(); - - sta = sta_info_get(local, ra); - if (!sta) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Could not find the station\n"); -#endif - ret = -ENOENT; - goto unlock; - } - /* * The aggregation code is not prepared to handle * anything but STA/AP due to the BSSID handling. * IBSS could work in the code but isn't supported * by drivers or the standard. */ - if (sta->sdata->vif.type != NL80211_IFTYPE_STATION && - sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN && - sta->sdata->vif.type != NL80211_IFTYPE_AP) { - ret = -EINVAL; - goto unlock; - } + if (sdata->vif.type != NL80211_IFTYPE_STATION && + sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + sdata->vif.type != NL80211_IFTYPE_AP) + return -EINVAL; if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Suspend in progress. " "Denying BA session request\n"); #endif - ret = -EINVAL; - goto unlock; + return -EINVAL; } spin_lock_bh(&sta->lock); spin_lock(&local->ampdu_lock); - sdata = sta->sdata; - /* we have tried too many times, receiver does not want A-MPDU */ if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { ret = -EBUSY; @@ -310,8 +296,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) start_seq_num = sta->tid_seq[tid]; - ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START, - &sta->sta, tid, &start_seq_num); + ret = drv_ampdu_action(local, &sdata->vif, + IEEE80211_AMPDU_TX_START, + pubsta, tid, &start_seq_num); if (ret) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -336,7 +323,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta->ampdu_mlme.dialog_token_allocator; sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; - ieee80211_send_addba_request(sta->sdata, ra, tid, + ieee80211_send_addba_request(sdata, pubsta->addr, tid, sta->ampdu_mlme.tid_tx[tid]->dialog_token, sta->ampdu_mlme.tid_tx[tid]->ssn, 0x40, 5000); @@ -348,7 +335,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); #endif - goto unlock; + return 0; err_free: kfree(sta->ampdu_mlme.tid_tx[tid]); @@ -360,8 +347,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) err_unlock_sta: spin_unlock(&local->ampdu_lock); spin_unlock_bh(&sta->lock); - unlock: - rcu_read_unlock(); return ret; } EXPORT_SYMBOL(ieee80211_start_tx_ba_session); @@ -428,13 +413,15 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, ieee80211_agg_splice_finish(local, sta, tid); spin_unlock(&local->ampdu_lock); - drv_ampdu_action(local, IEEE80211_AMPDU_TX_OPERATIONAL, + drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_TX_OPERATIONAL, &sta->sta, tid, NULL); } -void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) +void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; u8 *state; @@ -483,10 +470,11 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) } EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); -void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct ieee80211_ra_tid *ra_tid; struct sk_buff *skb = dev_alloc_skb(0); @@ -535,13 +523,12 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, return ret; } -int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, - u8 *ra, u16 tid, +int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, enum ieee80211_back_parties initiator) { - struct ieee80211_local *local = hw_to_local(hw); - struct sta_info *sta; - int ret = 0; + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; if (WARN_ON(!local->ops->ampdu_action)) return -EINVAL; @@ -549,22 +536,14 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, if (tid >= STA_TID_NUM) return -EINVAL; - rcu_read_lock(); - sta = sta_info_get(local, ra); - if (!sta) { - rcu_read_unlock(); - return -ENOENT; - } - - ret = __ieee80211_stop_tx_ba_session(sta, tid, initiator); - rcu_read_unlock(); - return ret; + return __ieee80211_stop_tx_ba_session(sta, tid, initiator); } EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); -void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) +void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; u8 *state; @@ -627,10 +606,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) } EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); -void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct ieee80211_ra_tid *ra_tid; struct sk_buff *skb = dev_alloc_skb(0); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 020a94a31106..921dd9c9ff62 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -239,15 +239,16 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local) } static inline int drv_ampdu_action(struct ieee80211_local *local, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { int ret = -EOPNOTSUPP; if (local->ops->ampdu_action) - ret = local->ops->ampdu_action(&local->hw, action, + ret = local->ops->ampdu_action(&local->hw, vif, action, sta, tid, ssn); - trace_drv_ampdu_action(local, action, sta, tid, ssn, ret); + trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret); return ret; } diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 37b9051afcf3..b8fef1d11369 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -634,11 +634,12 @@ TRACE_EVENT(drv_tx_last_beacon, TRACE_EVENT(drv_ampdu_action, TP_PROTO(struct ieee80211_local *local, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, int ret), - TP_ARGS(local, action, sta, tid, ssn, ret), + TP_ARGS(local, vif, action, sta, tid, ssn, ret), TP_STRUCT__entry( LOCAL_ENTRY @@ -647,10 +648,12 @@ TRACE_EVENT(drv_ampdu_action, __field(u16, tid) __field(u16, ssn) __field(int, ret) + VIF_ENTRY ), TP_fast_assign( LOCAL_ASSIGN; + VIF_ASSIGN; STA_ASSIGN; __entry->ret = ret; __entry->action = action; @@ -659,8 +662,8 @@ TRACE_EVENT(drv_ampdu_action, ), TP_printk( - LOCAL_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d", - LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d", + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret ) ); #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 48ef1a282b91..345c8ee50175 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -141,7 +141,6 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_mgmt *mgmt, size_t len) { - struct ieee80211_local *local = sdata->local; u16 tid, params; u16 initiator; @@ -164,7 +163,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, sta->ampdu_mlme.tid_state_tx[tid] = HT_AGG_STATE_OPERATIONAL; spin_unlock_bh(&sta->lock); - ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, tid, + ieee80211_stop_tx_ba_session(&sta->sta, tid, WLAN_BACK_RECIPIENT); } } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b63b99fb2fd3..b7598db5ade2 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -771,8 +771,9 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) return netdev_priv(dev); } -/* this struct represents 802.11n's RA/TID combination */ +/* this struct represents 802.11n's RA/TID combination along with our vif */ struct ieee80211_ra_tid { + struct ieee80211_vif *vif; u8 ra[ETH_ALEN]; u16 tid; }; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c74a6a1935b3..f4be97c3b747 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -296,14 +296,14 @@ static void ieee80211_tasklet_handler(unsigned long data) break; case IEEE80211_DELBA_MSG: ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - ieee80211_stop_tx_ba_cb(local_to_hw(local), - ra_tid->ra, ra_tid->tid); + ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra, + ra_tid->tid); dev_kfree_skb(skb); break; case IEEE80211_ADDBA_MSG: ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - ieee80211_start_tx_ba_cb(local_to_hw(local), - ra_tid->ra, ra_tid->tid); + ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra, + ra_tid->tid); dev_kfree_skb(skb); break ; default: -- cgit v1.2.3 From 5be83de54c16944dea9c16c6a5a53c1fa75ed304 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Nov 2009 00:56:28 +0100 Subject: cfg80211: convert bools into flags We've accumulated a number of options for wiphys which make more sense as flags as we keep adding more. Convert the existing ones. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 5 +-- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 +-- drivers/net/wireless/mac80211_hwsim.c | 18 ++++----- drivers/net/wireless/p54/main.c | 2 +- include/net/cfg80211.h | 62 ++++++++++++++++------------- net/mac80211/main.c | 2 +- net/wireless/Kconfig | 6 --- net/wireless/core.c | 13 ++++-- net/wireless/nl80211.c | 2 +- net/wireless/reg.c | 13 +++--- 11 files changed, 70 insertions(+), 67 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 077bcc142cde..039ac490465c 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -450,7 +450,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, const struct ieee80211_regdomain *regd; wiphy->reg_notifier = reg_notifier; - wiphy->strict_regulatory = true; + wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; if (ath_is_world_regd(reg)) { /* @@ -458,8 +458,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, * saved on the wiphy orig_* parameters */ regd = ath_world_regdomain(reg); - wiphy->custom_regulatory = true; - wiphy->strict_regulatory = false; + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; } else { /* * This gets applied in the case of the absense of CRDA, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b80cd0bc5845..e8f405a01e3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2400,16 +2400,14 @@ static int iwl_setup_mac(struct iwl_priv *priv) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->custom_regulatory = true; - - /* Firmware does not support this */ - hw->wiphy->disable_beacon_hints = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | + WIPHY_FLAG_DISABLE_BEACON_HINTS; /* * For now, disable PS by default because it affects * RX performance significantly. */ - hw->wiphy->ps_default = false; + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; /* we create the 802.11 header and a zero-length SSID element */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 31f3c42b835c..5b7e80e5bab4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3904,10 +3904,8 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->custom_regulatory = true; - - /* Firmware does not support this */ - hw->wiphy->disable_beacon_hints = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | + WIPHY_FLAG_DISABLE_BEACON_HINTS; hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; /* we create the 802.11 header and a zero-length SSID element */ diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index fc4ec48eda12..88e41176e7fd 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1146,46 +1146,46 @@ static int __init init_mac80211_hwsim(void) break; case HWSIM_REGTEST_WORLD_ROAM: if (i == 0) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } break; case HWSIM_REGTEST_CUSTOM_WORLD: - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); break; case HWSIM_REGTEST_CUSTOM_WORLD_2: if (i == 0) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } else if (i == 1) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_02); } break; case HWSIM_REGTEST_STRICT_ALL: - hw->wiphy->strict_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; break; case HWSIM_REGTEST_STRICT_FOLLOW: case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: if (i == 0) - hw->wiphy->strict_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; break; case HWSIM_REGTEST_ALL: if (i == 0) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } else if (i == 1) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_02); } else if (i == 4) - hw->wiphy->strict_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; break; default: break; diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 4d486bf9f725..18012dbfb45d 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -579,7 +579,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) * For now, disable PS by default because it affects * link stability significantly. */ - dev->wiphy->ps_default = false; + dev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; mutex_init(&priv->conf_mutex); mutex_init(&priv->eeprom_mutex); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 21710fc17eaf..eca36abca8f5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1108,27 +1108,45 @@ struct cfg80211_ops { */ /** - * struct wiphy - wireless hardware description - * @idx: the wiphy index assigned to this item - * @class_dev: the class device representing /sys/class/ieee80211/ - * @custom_regulatory: tells us the driver for this device + * enum wiphy_flags - wiphy capability flags + * + * @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device * has its own custom regulatory domain and cannot identify the * ISO / IEC 3166 alpha2 it belongs to. When this is enabled * we will disregard the first regulatory hint (when the * initiator is %REGDOM_SET_BY_CORE). - * @strict_regulatory: tells us the driver for this device will ignore - * regulatory domain settings until it gets its own regulatory domain - * via its regulatory_hint(). After its gets its own regulatory domain - * it will only allow further regulatory domain settings to further - * enhance compliance. For example if channel 13 and 14 are disabled - * by this regulatory domain no user regulatory domain can enable these - * channels at a later time. This can be used for devices which do not - * have calibration information gauranteed for frequencies or settings - * outside of its regulatory domain. - * @disable_beacon_hints: enable this if your driver needs to ensure that - * passive scan flags and beaconing flags may not be lifted by cfg80211 - * due to regulatory beacon hints. For more information on beacon + * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will + * ignore regulatory domain settings until it gets its own regulatory + * domain via its regulatory_hint(). After its gets its own regulatory + * domain it will only allow further regulatory domain settings to + * further enhance compliance. For example if channel 13 and 14 are + * disabled by this regulatory domain no user regulatory domain can + * enable these channels at a later time. This can be used for devices + * which do not have calibration information gauranteed for frequencies + * or settings outside of its regulatory domain. + * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure + * that passive scan flags and beaconing flags may not be lifted by + * cfg80211 due to regulatory beacon hints. For more information on beacon * hints read the documenation for regulatory_hint_found_beacon() + * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this + * wiphy at all + * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled + * by default -- this flag will be set depending on the kernel's default + * on wiphy_new(), but can be changed by the driver if it has a good + * reason to override the default + */ +enum wiphy_flags { + WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), + WIPHY_FLAG_STRICT_REGULATORY = BIT(1), + WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2), + WIPHY_FLAG_NETNS_OK = BIT(3), + WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), +}; + +/** + * struct wiphy - wireless hardware description + * @idx: the wiphy index assigned to this item + * @class_dev: the class device representing /sys/class/ieee80211/ * @reg_notifier: the driver's regulatory notification callback * @regd: the driver's regulatory domain, if one was requested via * the regulatory_hint() API. This can be used by the driver @@ -1143,11 +1161,6 @@ struct cfg80211_ops { * -1 = fragmentation disabled, only odd values >= 256 used * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled * @net: the network namespace this wiphy currently lives in - * @netnsok: if set to false, do not allow changing the netns of this - * wiphy at all - * @ps_default: default for powersave, will be set depending on the - * kernel's default on wiphy_new(), but can be changed by the - * driver if it has a good reason to override the default */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -1158,12 +1171,7 @@ struct wiphy { /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ u16 interface_modes; - bool custom_regulatory; - bool strict_regulatory; - bool disable_beacon_hints; - - bool netnsok; - bool ps_default; + u32 flags; enum cfg80211_signal_type signal_type; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e843a912849c..8084b622e97e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -328,7 +328,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, if (!wiphy) return NULL; - wiphy->netnsok = true; + wiphy->flags |= WIPHY_FLAG_NETNS_OK; wiphy->privid = mac80211_wiphy_privid; /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 614bdcec1c80..90e93a5701aa 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -74,12 +74,6 @@ config CFG80211_REG_DEBUG If unsure, say N. -config CFG80211_DEFAULT_PS_VALUE - int - default 1 if CFG80211_DEFAULT_PS - default 0 - depends on CFG80211 - config CFG80211_DEFAULT_PS bool "enable powersave by default" depends on CFG80211 diff --git a/net/wireless/core.c b/net/wireless/core.c index 02835172b227..e2cc6e7522dd 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -230,7 +230,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev; int err = 0; - if (!rdev->wiphy.netnsok) + if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) return -EOPNOTSUPP; list_for_each_entry(wdev, &rdev->netdev_list, list) { @@ -367,7 +367,9 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) rdev->wiphy.dev.class = &ieee80211_class; rdev->wiphy.dev.platform_data = rdev; - rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE; +#ifdef CONFIG_CFG80211_DEFAULT_PS + rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; +#endif wiphy_net_set(&rdev->wiphy, &init_net); @@ -482,7 +484,7 @@ int wiphy_register(struct wiphy *wiphy) if (IS_ERR(rdev->wiphy.debugfsdir)) rdev->wiphy.debugfsdir = NULL; - if (wiphy->custom_regulatory) { + if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { struct regulatory_request request; request.wiphy_idx = get_wiphy_idx(wiphy); @@ -680,7 +682,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev->wext.default_key = -1; wdev->wext.default_mgmt_key = -1; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; - wdev->wext.ps = wdev->wiphy->ps_default; + if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT) + wdev->wext.ps = true; + else + wdev->wext.ps = false; wdev->wext.ps_timeout = 100; if (rdev->ops->set_power_mgmt) if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 37264d56bace..6634188f9453 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -561,7 +561,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(deauth, DEAUTHENTICATE); CMD(disassoc, DISASSOCIATE); CMD(join_ibss, JOIN_IBSS); - if (dev->wiphy.netnsok) { + if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { i++; NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); } diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f256dfffbf46..1f33017737fd 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1008,7 +1008,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && request_wiphy && request_wiphy == wiphy && - request_wiphy->strict_regulatory) { + request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { /* * This gaurantees the driver's requested regulatory domain * will always be used as a base for further regulatory @@ -1051,13 +1051,13 @@ static bool ignore_reg_update(struct wiphy *wiphy, if (!last_request) return true; if (initiator == NL80211_REGDOM_SET_BY_CORE && - wiphy->custom_regulatory) + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) return true; /* * wiphy->regd will be set once the device has its own * desired regulatory domain set */ - if (wiphy->strict_regulatory && !wiphy->regd && + if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && !is_world_regdom(last_request->alpha2)) return true; return false; @@ -1093,7 +1093,7 @@ static void handle_reg_beacon(struct wiphy *wiphy, chan->beacon_found = true; - if (wiphy->disable_beacon_hints) + if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS) return; chan_before.center_freq = chan->center_freq; @@ -1164,7 +1164,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy) return true; if (last_request && last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && - wiphy->custom_regulatory) + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) return true; return false; } @@ -1591,7 +1591,8 @@ static void reg_process_hint(struct regulatory_request *reg_request) r = __regulatory_hint(wiphy, reg_request); /* This is required so that the orig_* parameters are saved */ - if (r == -EALREADY && wiphy && wiphy->strict_regulatory) + if (r == -EALREADY && wiphy && + wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) wiphy_update_regulatory(wiphy, reg_request->initiator); out: mutex_unlock(®_mutex); -- cgit v1.2.3 From 4e03185fb8e85d5624d3a68feced70cc9c9e2136 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 20 Nov 2009 12:04:52 -0800 Subject: iwlwifi: Add iwl_write8() To support byte writes to CSR_INT_COALESCING and CSR_INT_PERIODIC registers, add iwl_write8(), including debug/trace support. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-devtrace.c | 1 + drivers/net/wireless/iwlwifi/iwl-devtrace.h | 16 ++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-io.h | 20 ++++++++++++++++++++ 3 files changed, 37 insertions(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 4ef5acaa556d..e7d88d1da15d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -5,6 +5,7 @@ #define CREATE_TRACE_POINTS #include "iwl-devtrace.h" +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx); diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 8c7159208da1..f2d4b01ba466 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -32,6 +32,22 @@ TRACE_EVENT(iwlwifi_dev_ioread32, TP_printk("[%p] read io[%#x] = %#x", __entry->priv, __entry->offs, __entry->val) ); +TRACE_EVENT(iwlwifi_dev_iowrite8, + TP_PROTO(struct iwl_priv *priv, u32 offs, u8 val), + TP_ARGS(priv, offs, val), + TP_STRUCT__entry( + PRIV_ENTRY + __field(u32, offs) + __field(u8, val) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->offs = offs; + __entry->val = val; + ), + TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val) +); + TRACE_EVENT(iwlwifi_dev_iowrite32, TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val), TP_ARGS(priv, offs, val), diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index d0a358c9d96b..e552d4c4bdbe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -62,6 +62,26 @@ * */ +static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) +{ + trace_iwlwifi_dev_iowrite8(priv, ofs, val); + iowrite8(val, priv->hw_base + ofs); +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv, + u32 ofs, u8 val) +{ + IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l); + _iwl_write8(priv, ofs, val); +} +#define iwl_write8(priv, ofs, val) \ + __iwl_write8(__FILE__, __LINE__, priv, ofs, val) +#else +#define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val) +#endif + + static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) { trace_iwlwifi_dev_iowrite32(priv, ofs, val); -- cgit v1.2.3 From 74ba67edfcb235c0415a62d37493866c8380dc1d Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 20 Nov 2009 12:04:53 -0800 Subject: iwlagn: Use iwl_write8() for CSR_INT_COALESCING register CSR_INT_COALESCING previously had only one, but now has two single-byte fields. With only one single-byte field (lowest order byte) it was okay to write via iwl_write32(), but now with two, an iwl_write32() to the lower order field clobbers the other field (odd-address CSR_INT_PERIODIC_REG, offset 0x5), and an iwl_write32() to CSR_INT_PERIODIC_REG could clobber the lowest byte of the next-higher register (CSR_INT, offset 0x8). Fortunately, no bad side effects have been produced by the iwl_write32() usage, due to order of execution (low order byte was always written before higher order byte), and the fact that writing "0" to the low byte of the next higher register has no effect (only action is when writing "1"s). Nonetheless, this cleans up the accesses so no bad side effects might occur in the future, if execution order changes, or more bit fields get added to CSR_INT_COALESCING. Add some comments regarding periodic interrupt usage. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 19 ++++++++++++++----- drivers/net/wireless/iwlwifi/iwl-core.c | 5 ++++- drivers/net/wireless/iwlwifi/iwl-csr.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-rx.c | 3 ++- 4 files changed, 22 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e8f405a01e3d..a4e8db35a559 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1266,15 +1266,24 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) * 3- update RX shared data to indicate last write index. * 4- send interrupt. * This could lead to RX race, driver could receive RX interrupt - * but the shared data changes does not reflect this. - * this could lead to RX race, RX periodic will solve this race + * but the shared data changes does not reflect this; + * periodic interrupt will detect any dangling Rx activity. */ - iwl_write32(priv, CSR_INT_PERIODIC_REG, + + /* Disable periodic interrupt; we use it as just a one-shot. */ + iwl_write8(priv, CSR_INT_PERIODIC_REG, CSR_INT_PERIODIC_DIS); iwl_rx_handle(priv); - /* Only set RX periodic if real RX is received. */ + + /* + * Enable periodic interrupt in 8 msec only if we received + * real RX interrupt (instead of just periodic int), to catch + * any dangling Rx interrupt. If it was just the periodic + * interrupt, there was no dangling Rx activity, and no need + * to extend the periodic interrupt; one-shot is enough. + */ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) - iwl_write32(priv, CSR_INT_PERIODIC_REG, + iwl_write8(priv, CSR_INT_PERIODIC_REG, CSR_INT_PERIODIC_ENA); priv->isr_stats.rx++; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a2636f4b068f..c25cab5d0451 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -255,7 +255,10 @@ int iwl_hw_nic_init(struct iwl_priv *priv) /* nic_init */ spin_lock_irqsave(&priv->lock, flags); priv->cfg->ops->lib->apm_ops.init(priv); - iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); + + /* Set interrupt coalescing timer to 512 usecs */ + iwl_write8(priv, CSR_INT_COALESCING, 512 / 32); + spin_unlock_irqrestore(&priv->lock, flags); ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 68ed82206723..a7bfae01f19b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -173,8 +173,8 @@ #define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ -#define CSR_INT_PERIODIC_DIS (0x00) -#define CSR_INT_PERIODIC_ENA (0xFF) +#define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ +#define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), * acknowledged (reset) by host writing "1" to flagged bits. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index cc980d5d57c2..6090bc15a6d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -477,7 +477,8 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); - iwl_write32(priv, CSR_INT_COALESCING, 0x40); + /* Set interrupt coalescing timer to 64 x 32 = 2048 usecs */ + iwl_write8(priv, CSR_INT_COALESCING, 0x40); return 0; } -- cgit v1.2.3 From d5f4cf71f7b70e13f96cc8aac65b390707d5d80b Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:04:54 -0800 Subject: iwlwifi: control led while update tx/rx bytes counts LED blinking rate is based on tx/rx traffic, the most reasonable place to do it is after update the traffic byte counts This fixes the recent LED blinking breakage on 3945 introduced by "iwlwifi: separate led function from statistic notification" Signed-off-by: Wey-Yi Guy Tested-by: Maxim Levitsky Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 -- drivers/net/wireless/iwlwifi/iwl-core.c | 1 + drivers/net/wireless/iwlwifi/iwl-core.h | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a4e8db35a559..c41ec5e258b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1078,7 +1078,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { iwl_rx_handle(priv); priv->isr_stats.rx++; - iwl_leds_background(priv); handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } @@ -1287,7 +1286,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) CSR_INT_PERIODIC_ENA); priv->isr_stats.rx++; - iwl_leds_background(priv); } /* This "Tx" DMA channel is used only for loading uCode */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c25cab5d0451..7ac6b369890a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -3187,6 +3187,7 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) stats->data_cnt++; stats->data_bytes += len; } + iwl_leds_background(priv); } EXPORT_SYMBOL(iwl_update_stats); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 584a376b96c5..f271663c1d2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -390,6 +390,7 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx, /* data */ stats->data_bytes += len; } + iwl_leds_background(priv); } #endif /***************************************************** -- cgit v1.2.3 From c15d20c1d19616f73b6fee4befd254d0c37b4d87 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:04:55 -0800 Subject: iwlwifi: set sm_ps_mode as part of cfg parameters Setting "Spatial multiplexing Power Save" as part of per device configuration parameter. Report to uCode based on priv->conf setting, so driver can have more control of how different devices should operate in power save mode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 4 +++ drivers/net/wireless/iwlwifi/iwl-6000.c | 4 ++- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 --- drivers/net/wireless/iwlwifi/iwl-core.c | 45 ++++++++++++++------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 4 +-- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 8 files changed, 30 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 8f82537045bf..8414178bcff4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -173,6 +173,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl1000_bg_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1e58c49dd768..d1fab4e19204 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2238,6 +2238,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .broken_powersave = true, .led_compensation = 61, .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 570eaa08531f..90c7b897736d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1597,6 +1597,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5100_bg_cfg = { @@ -1666,6 +1667,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1689,6 +1691,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1712,6 +1715,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; 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 4ab9897f4fe1..74e571049273 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -306,6 +306,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -394,7 +395,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .support_sm_ps = true, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -454,6 +455,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c41ec5e258b1..7301aa73ab7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3135,10 +3135,6 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->band = IEEE80211_BAND_2GHZ; priv->iw_mode = NL80211_IFTYPE_STATION; - if (priv->cfg->support_sm_ps) - priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DYNAMIC; - else - priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7ac6b369890a..dbe41cf8943c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -449,13 +449,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, if (priv->cfg->ht_greenfield_support) ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - if (priv->cfg->support_sm_ps) - ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & - (WLAN_HT_CAP_SM_PS_DYNAMIC << 2)); - else - ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & - (WLAN_HT_CAP_SM_PS_DISABLED << 2)); - + ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & + (priv->cfg->sm_ps_mode << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; if (priv->hw_params.ht40_channel & BIT(band)) { ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; @@ -1010,25 +1005,23 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) int idle_cnt = active_cnt; bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); - if (priv->cfg->support_sm_ps) { - /* # Rx chains when idling and maybe trying to save power */ - switch (priv->current_ht_config.sm_ps) { - case WLAN_HT_CAP_SM_PS_STATIC: - case WLAN_HT_CAP_SM_PS_DYNAMIC: - idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : - IWL_NUM_IDLE_CHAINS_SINGLE; - break; - case WLAN_HT_CAP_SM_PS_DISABLED: - idle_cnt = (is_cam) ? active_cnt : - IWL_NUM_IDLE_CHAINS_SINGLE; - break; - case WLAN_HT_CAP_SM_PS_INVALID: - default: - IWL_ERR(priv, "invalid sm_ps mode %d\n", - priv->current_ht_config.sm_ps); - WARN_ON(1); - break; - } + /* # Rx chains when idling and maybe trying to save power */ + switch (priv->cfg->sm_ps_mode) { + case WLAN_HT_CAP_SM_PS_STATIC: + idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; + break; + case WLAN_HT_CAP_SM_PS_DYNAMIC: + idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : + IWL_NUM_IDLE_CHAINS_SINGLE; + break; + case WLAN_HT_CAP_SM_PS_DISABLED: + break; + case WLAN_HT_CAP_SM_PS_INVALID: + default: + IWL_ERR(priv, "invalid sm_ps mode %u\n", + priv->cfg->sm_ps_mode); + WARN_ON(1); + break; } return idle_cnt; } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f271663c1d2f..334da64d968d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -228,7 +228,7 @@ struct iwl_mod_params { * @chain_noise_num_beacons: number of beacons used to compute chain noise * @adv_thermal_throttle: support advance thermal throttle * @support_ct_kill_exit: support ct kill exit condition - * @support_sm_ps: support spatial multiplexing power save + * @sm_ps_mode: spatial multiplexing power save mode * @support_wimax_coexist: support wimax/wifi co-exist * * We enable the driver to be backward compatible wrt API version. The @@ -285,7 +285,7 @@ struct iwl_cfg { const bool supports_idle; bool adv_thermal_throttle; bool support_ct_kill_exit; - bool support_sm_ps; + u8 sm_ps_mode; const bool support_wimax_coexist; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f1601cfebc29..1c1ed4bfcb08 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -511,7 +511,6 @@ struct iwl_ht_config { bool is_ht; bool is_40mhz; bool single_chain_sufficient; - u8 sm_ps; /* BSS related data */ u8 extension_chan_offset; u8 ht_protection; -- cgit v1.2.3 From 7163b8a4ec995dabda3e92c6fed7b8600060618c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:04:56 -0800 Subject: iwlwifi: reset led_tpt when clear tx/rx traffic byte counts LED blink rate is based on the traffic load, when tx/rx traffic counts got reset, we also need to reset the led_tpt to prevent incorrect blink rate being calculated. Merge both clear_tx_statistics() and clear_rx_statistics() into single clear_traffic_statistics() function, when reset the traffic byte counts, both tx and rx need to be reset at the same time, to make sure calculated the correct led blink rate. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 8 ++---- drivers/net/wireless/iwlwifi/iwl-core.h | 3 +-- drivers/net/wireless/iwlwifi/iwl-debug.h | 3 ++- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 42 +++++++++--------------------- 4 files changed, 18 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index dbe41cf8943c..c2263180614e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -3079,15 +3079,11 @@ const char *get_ctrl_string(int cmd) } } -void iwl_clear_tx_stats(struct iwl_priv *priv) +void iwl_clear_traffic_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)); + priv->led_tpt = 0; } /* diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 334da64d968d..0779158fed2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -353,8 +353,7 @@ 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_clear_traffic_stats(struct iwl_priv *priv); void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len); #else diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 25a0e73314f7..d61293ab67c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -107,7 +107,8 @@ struct iwl_debugfs { struct dentry *file_chain_noise; struct dentry *file_tx_power; struct dentry *file_power_save_status; - struct dentry *file_clear_statistics; + struct dentry *file_clear_ucode_statistics; + struct dentry *file_clear_traffic_statistics; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 9a5ca25d72c3..b8f9edc3d998 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -160,7 +160,7 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, return ret; } -static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file, +static ssize_t iwl_dbgfs_clear_traffic_statistics_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -175,8 +175,7 @@ static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file, return -EFAULT; if (sscanf(buf, "%x", &clear_flag) != 1) return -EFAULT; - if (clear_flag == 1) - iwl_clear_tx_stats(priv); + iwl_clear_traffic_stats(priv); return count; } @@ -221,26 +220,6 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, 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; #define BYTE2_MASK 0x0000ffff; #define BYTE3_MASK 0x00ffffff; @@ -1823,7 +1802,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_clear_statistics_write(struct file *file, +static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -1847,8 +1826,8 @@ static ssize_t iwl_dbgfs_clear_statistics_write(struct file *file, return count; } -DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); -DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); +DEBUGFS_READ_FILE_OPS(rx_statistics); +DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); DEBUGFS_READ_FILE_OPS(rx_queue); DEBUGFS_READ_FILE_OPS(tx_queue); @@ -1859,7 +1838,8 @@ DEBUGFS_READ_FILE_OPS(sensitivity); DEBUGFS_READ_FILE_OPS(chain_noise); DEBUGFS_READ_FILE_OPS(tx_power); DEBUGFS_READ_FILE_OPS(power_save_status); -DEBUGFS_WRITE_FILE_OPS(clear_statistics); +DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics); +DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); /* * Create the debugfs files and directories @@ -1908,7 +1888,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(tx_queue, debug); DEBUGFS_ADD_FILE(tx_power, debug); DEBUGFS_ADD_FILE(power_save_status, debug); - DEBUGFS_ADD_FILE(clear_statistics, debug); + DEBUGFS_ADD_FILE(clear_ucode_statistics, debug); + DEBUGFS_ADD_FILE(clear_traffic_statistics, 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); @@ -1962,7 +1943,10 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_clear_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_clear_ucode_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_clear_traffic_statistics); 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); -- cgit v1.2.3 From bc6c94f609d2f63347d4a05f28993792ae38caad Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 20 Nov 2009 12:04:57 -0800 Subject: iwl3945: removed unused struct and definitions Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 9 --------- drivers/net/wireless/iwlwifi/iwl-dev.h | 8 -------- 2 files changed, 17 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 2b0d65c5780a..a41f0e098cf6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -221,19 +221,10 @@ struct iwl3945_ibss_seq { * for use by iwl-*.c * *****************************************************************************/ -extern int iwl3945_power_init_handle(struct iwl_priv *priv); -extern int iwl3945_eeprom_init(struct iwl_priv *priv); extern int iwl3945_calc_db_from_ratio(int sig_ratio); extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm); -extern int iwl3945_tx_queue_init(struct iwl_priv *priv, - struct iwl_tx_queue *txq, int count, u32 id); extern void iwl3945_rx_replenish(void *data); extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); -extern void iwl3945_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq); -extern int iwl3945_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, - const void *data); -extern int __must_check iwl3945_send_cmd(struct iwl_priv *priv, - struct iwl_host_cmd *cmd); extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr,int left); extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1c1ed4bfcb08..4ded1900540d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -544,14 +544,6 @@ struct iwl_qos_info { struct iwl_qosparam_cmd def_qos_parm; }; - -struct iwl3945_station_entry { - struct iwl3945_addsta_cmd sta; - struct iwl_tid_data tid[MAX_TID_COUNT]; - u8 used; - struct iwl_hw_key keyinfo; -}; - struct iwl_station_entry { struct iwl_addsta_cmd sta; struct iwl_tid_data tid[MAX_TID_COUNT]; -- cgit v1.2.3 From 43e851157adb966dd633e983b24040f72877737e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:04:58 -0800 Subject: iwlwifi: set read/write permission for debugfs files Set the correct Read/Write file permission for iwlwifi debugfs files based on the functionality of the files Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 8 ++--- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 58 +++++++++++++++--------------- 2 files changed, 33 insertions(+), 33 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 2f09e3b7f0eb..fe511cbf012e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2964,16 +2964,16 @@ static void rs_add_debugfs(void *priv, void *priv_sta, { struct iwl_lq_sta *lq_sta = priv_sta; lq_sta->rs_sta_dbgfs_scale_table_file = - debugfs_create_file("rate_scale_table", 0600, dir, + debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, lq_sta, &rs_sta_dbgfs_scale_table_ops); lq_sta->rs_sta_dbgfs_stats_table_file = - debugfs_create_file("rate_stats_table", 0600, dir, + debugfs_create_file("rate_stats_table", S_IRUSR, dir, lq_sta, &rs_sta_dbgfs_stats_table_ops); lq_sta->rs_sta_dbgfs_rate_scale_data_file = - debugfs_create_file("rate_scale_data", 0600, dir, + debugfs_create_file("rate_scale_data", S_IRUSR, dir, lq_sta, &rs_sta_dbgfs_rate_scale_data_ops); lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = - debugfs_create_u8("tx_agg_tid_enable", 0600, dir, + debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, &lq_sta->tx_agg_tid_en); } diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index b8f9edc3d998..e6194c8e7f72 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -47,9 +47,9 @@ goto err; \ } while (0) -#define DEBUGFS_ADD_FILE(name, parent) do { \ +#define DEBUGFS_ADD_FILE(name, parent, mode) do { \ dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_file(#name, S_IWUSR | S_IRUSR, \ + debugfs_create_file(#name, mode, \ dbgfs->dir_##parent, priv, \ &iwl_dbgfs_##name##_ops); \ if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \ @@ -1868,34 +1868,34 @@ 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(channels, data); - DEBUGFS_ADD_FILE(status, data); - DEBUGFS_ADD_FILE(interrupt, data); - DEBUGFS_ADD_FILE(qos, data); - DEBUGFS_ADD_FILE(led, data); - 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); - DEBUGFS_ADD_FILE(power_save_status, debug); - DEBUGFS_ADD_FILE(clear_ucode_statistics, debug); - DEBUGFS_ADD_FILE(clear_traffic_statistics, debug); + DEBUGFS_ADD_FILE(nvm, data, S_IRUSR); + DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(log_event, data, S_IWUSR); + DEBUGFS_ADD_FILE(stations, data, S_IRUSR); + DEBUGFS_ADD_FILE(channels, data, S_IRUSR); + DEBUGFS_ADD_FILE(status, data, S_IRUSR); + DEBUGFS_ADD_FILE(interrupt, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(qos, data, S_IRUSR); + DEBUGFS_ADD_FILE(led, data, S_IRUSR); + DEBUGFS_ADD_FILE(sleep_level_override, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(current_sleep_command, data, S_IRUSR); + DEBUGFS_ADD_FILE(thermal_throttling, data, S_IRUSR); + DEBUGFS_ADD_FILE(disable_ht40, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rx_statistics, debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_statistics, debug, S_IRUSR); + DEBUGFS_ADD_FILE(traffic_log, debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rx_queue, debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_queue, debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_power, debug, S_IRUSR); + DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR); + DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR); + DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR); 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_FILE(ucode_rx_stats, debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR); + DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR); + DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR); } DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, -- cgit v1.2.3 From d23db556819c00d297c0f447bdd75b282d563122 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:04:59 -0800 Subject: iwlwifi: increase tx_queue debugfs buffer size For tx_queue, need to increase the buffer size allocated for it, so all the queues information can be displayed Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index e6194c8e7f72..4630094b4ca1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -964,7 +964,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, int pos = 0; int cnt; int ret; - const size_t bufsz = sizeof(char) * 60 * priv->cfg->num_of_queues; + const size_t bufsz = sizeof(char) * 64 * priv->cfg->num_of_queues; if (!priv->txq) { IWL_ERR(priv, "txq not ready\n"); -- cgit v1.2.3 From 2943f136ffe29adb08162197b129bf8106e8191c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:00 -0800 Subject: iwlwifi: dynamically allocate buffer for sram debugfs file Dynamically allocate memory for dumping SRAM based on the length of memory to be displayed. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 4630094b4ca1..016ff4014a7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -228,13 +228,21 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, size_t count, loff_t *ppos) { u32 val; - char buf[1024]; + char *buf; ssize_t ret; int i; int pos = 0; struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - const size_t bufsz = sizeof(buf); + size_t bufsz; + bufsz = 30 + priv->dbgfs->sram_len * sizeof(char) * 12; + buf = kmalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + pos += scnprintf(buf + pos, bufsz - pos, "sram_len: %d\n", + priv->dbgfs->sram_len); + pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: %d\n", + priv->dbgfs->sram_offset); for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ priv->dbgfs->sram_len - i); @@ -251,11 +259,14 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, break; } } + if (!(i % 16)) + pos += scnprintf(buf + pos, bufsz - pos, "\n"); pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val); } pos += scnprintf(buf + pos, bufsz - pos, "\n"); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); return ret; } -- cgit v1.2.3 From 6262408392aa66083c9d5db101755fe753c97d4e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:01 -0800 Subject: iwlwifi: fix reserved2 field in iwl4965_addsta reserved2 field in "struct iwl4965_addsta_cmd" is __le16. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d1fab4e19204..a8914898133e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1819,7 +1819,7 @@ static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn; addsta->sleep_tx_count = cmd->sleep_tx_count; addsta->reserved1 = cpu_to_le16(0); - addsta->reserved2 = cpu_to_le32(0); + addsta->reserved2 = cpu_to_le16(0); return (u16)sizeof(struct iwl4965_addsta_cmd); } -- cgit v1.2.3 From 0fd95afc7b8ae19045dc03ffeafb3afda78cb681 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Nov 2009 12:05:02 -0800 Subject: iwlwifi: separate IO tracing Since IO tracing is usually not needed and generates a lot of data, separate it into its own trace system so that we can always enable iwlwifi:* and not have to worry about getting too much data. If IO tracing is then really needed we can enable iwlwifi_io:* in addition and get that data. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-devtrace.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index f2d4b01ba466..21361968ab7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -14,7 +14,7 @@ static inline void trace_ ## name(proto) {} #define PRIV_ASSIGN __entry->priv = priv #undef TRACE_SYSTEM -#define TRACE_SYSTEM iwlwifi +#define TRACE_SYSTEM iwlwifi_io TRACE_EVENT(iwlwifi_dev_ioread32, TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val), @@ -64,6 +64,9 @@ TRACE_EVENT(iwlwifi_dev_iowrite32, TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val) ); +#undef TRACE_SYSTEM +#define TRACE_SYSTEM iwlwifi + TRACE_EVENT(iwlwifi_dev_hcmd, TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags), TP_ARGS(priv, hcmd, len, flags), -- cgit v1.2.3 From ac592574a577162183b5c1dd040a188caa068a29 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:03 -0800 Subject: iwlwifi: update supported PCI_ID list for 5xx0 series Update the PCI_ID list for 5xx0 series. Remove all the PCI_IDs which never made into production or not longer in production. Also make sure the supported bands(a/b/g/n) match specified PCI_IDs Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 29 +++++++++++-- drivers/net/wireless/iwlwifi/iwl-agn.c | 74 +++++++++++++++++++++++++-------- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 +- 3 files changed, 84 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 90c7b897736d..9175158f3580 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1600,12 +1600,12 @@ struct iwl_cfg iwl5300_agn_cfg = { .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; -struct iwl_cfg iwl5100_bg_cfg = { - .name = "5100BG", +struct iwl_cfg iwl5100_bgn_cfg = { + .name = "5100BGN", .fw_name_pre = IWL5000_FW_PRE, .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, - .sku = IWL_SKU_G, + .sku = IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, @@ -1641,7 +1641,6 @@ struct iwl_cfg iwl5100_abg_cfg = { .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .set_l0s = true, .use_bsm = false, - .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; @@ -1718,6 +1717,28 @@ struct iwl_cfg iwl5150_agn_cfg = { .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; +struct iwl_cfg iwl5150_abg_cfg = { + .name = "5150ABG", + .fw_name_pre = IWL5150_FW_PRE, + .ucode_api_max = IWL5150_UCODE_API_MAX, + .ucode_api_min = IWL5150_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G, + .ops = &iwl5150_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_AB, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, + .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, +}; + MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7301aa73ab7e..92f9df6a04a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3541,23 +3541,63 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, #endif /* CONFIG_IWL4965 */ #ifdef CONFIG_IWL5000 - {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)}, - {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)}, - {IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)}, - {IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)}, -/* 5350 WiFi/WiMax */ - {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, - {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, - {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, -/* 5150 Wifi/WiMax */ - {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)}, - {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, +/* 5100 Series WiFi */ + {IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1304, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bgn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bgn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1221, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1321, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1224, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1324, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1225, iwl5100_bgn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1325, iwl5100_bgn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1226, iwl5100_abg_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1211, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1311, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1214, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1314, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1215, iwl5100_bgn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1315, iwl5100_bgn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1316, iwl5100_abg_cfg)}, /* Half Mini Card */ + +/* 5300 Series WiFi */ + {IWL_PCI_DEVICE(0x4235, 0x1021, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1121, iwl5300_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1024, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1124, iwl5300_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1001, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1101, iwl5300_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1004, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1104, iwl5300_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4236, 0x1011, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4236, 0x1111, iwl5300_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4236, 0x1014, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4236, 0x1114, iwl5300_agn_cfg)}, /* Half Mini Card */ + +/* 5350 Series WiFi/WiMax */ + {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, /* Mini Card */ + +/* 5150 Series Wifi/WiMax */ + {IWL_PCI_DEVICE(0x423C, 0x1201, iwl5150_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1301, iwl5150_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1206, iwl5150_abg_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */ + + {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x423D, 0x1216, iwl5150_abg_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423D, 0x1316, iwl5150_abg_cfg)}, /* Half Mini Card */ /* 6x00 Series */ {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 4ded1900540d..2673e9a4db92 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -52,9 +52,10 @@ extern struct iwl_cfg iwl4965_agn_cfg; extern struct iwl_cfg iwl5300_agn_cfg; extern struct iwl_cfg iwl5100_agn_cfg; extern struct iwl_cfg iwl5350_agn_cfg; -extern struct iwl_cfg iwl5100_bg_cfg; +extern struct iwl_cfg iwl5100_bgn_cfg; extern struct iwl_cfg iwl5100_abg_cfg; extern struct iwl_cfg iwl5150_agn_cfg; +extern struct iwl_cfg iwl5150_abg_cfg; extern struct iwl_cfg iwl6000i_2agn_cfg; extern struct iwl_cfg iwl6000i_2abg_cfg; extern struct iwl_cfg iwl6000i_2bg_cfg; -- cgit v1.2.3 From 5ade1e4dd1df436c3a441d17321c24aac8497306 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:04 -0800 Subject: iwlwifi: by default, dump entire sram data portion For "sram" debugfs file, if user did not specify the offset and length, dump the entire data portion of sram by default. Data portion is 0x800000 - 0x80ffff, but the actual data size is known to the driver from the ucode file. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 016ff4014a7b..5adf0b606202 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -235,13 +235,21 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, struct iwl_priv *priv = (struct iwl_priv *)file->private_data; size_t bufsz; - bufsz = 30 + priv->dbgfs->sram_len * sizeof(char) * 12; + /* default is to dump the entire data segment */ + if (!priv->dbgfs->sram_offset && !priv->dbgfs->sram_len) { + priv->dbgfs->sram_offset = 0x800000; + if (priv->ucode_type == UCODE_INIT) + priv->dbgfs->sram_len = priv->ucode_init_data.len; + else + priv->dbgfs->sram_len = priv->ucode_data.len; + } + bufsz = 30 + priv->dbgfs->sram_len * sizeof(char) * 10; buf = kmalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; - pos += scnprintf(buf + pos, bufsz - pos, "sram_len: %d\n", + pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", priv->dbgfs->sram_len); - pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: %d\n", + pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", priv->dbgfs->sram_offset); for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ -- cgit v1.2.3 From 3a3ff72c18085563ce64f7456ae3afff3a83397e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:05 -0800 Subject: iwlwifi: dump error log when uCode error occurred uCode error log contain information as to what the error was and where it occurred necessary to debug any uCode issues. Always log the information without special debug flag, this can help to capture the important information when error happened. Signed-off-by: Wey-Yi Guy Acked-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.h | 6 +----- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 92f9df6a04a6..927131192572 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1604,7 +1604,6 @@ static int iwl_read_ucode(struct iwl_priv *priv) return ret; } -#ifdef CONFIG_IWLWIFI_DEBUG static const char *desc_lookup_text[] = { "OK", "FAIL", @@ -1697,6 +1696,8 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) } +#ifdef CONFIG_IWLWIFI_DEBUG + #define EVENT_START_OFFSET (4 * sizeof(u32)) /** diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c2263180614e..05a0c413cdf9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1361,9 +1361,9 @@ void iwl_irq_handle_error(struct iwl_priv *priv) /* Cancel currently queued command. */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + priv->cfg->ops->lib->dump_nic_error_log(priv); #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) { - priv->cfg->ops->lib->dump_nic_error_log(priv); priv->cfg->ops->lib->dump_nic_event_log(priv); iwl_print_rx_config_cmd(priv); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 0779158fed2f..ecba0f46bac5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -578,19 +578,15 @@ int iwl_pci_resume(struct pci_dev *pdev); /***************************************************** * Error Handling Debugging ******************************************************/ +void iwl_dump_nic_error_log(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_dump_nic_event_log(struct iwl_priv *priv); -void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_print_rx_config_cmd(struct iwl_priv *priv); #else static inline void iwl_dump_nic_event_log(struct iwl_priv *priv) { } -static inline void iwl_dump_nic_error_log(struct iwl_priv *priv) -{ -} - static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv) { } -- cgit v1.2.3 From 644c77f0cfa333e58fd4a09450434e89a52d8931 Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Fri, 20 Nov 2009 12:05:06 -0800 Subject: iwlwifi: Tell the ucode immediately when association state changes When we get a state change of associated or not, we need to tell the ucode via the RX_ON command using the filter flags. This will prevent the ucode from sending any packets when not associated, specifically not sending NULL QOS packets after a deauthentication which causes the AP to repeatedly send deauth's in some situations. Signed-off-by: Jay Sternberg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 05a0c413cdf9..2e0fb2804ad0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2478,6 +2478,16 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, } else { priv->assoc_id = 0; iwl_led_disassociate(priv); + + /* + * inform the ucode that there is no longer an + * association and that no more packets should be + * send + */ + priv->staging_rxon.filter_flags &= + ~RXON_FILTER_ASSOC_MSK; + priv->staging_rxon.assoc_id = 0; + iwlcore_commit_rxon(priv); } } -- cgit v1.2.3 From c341ddb283b9e1a6d217e73fa36738629ca8f4fb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:07 -0800 Subject: iwlwifi: print limited number of event log when uCode error To help iwlagn uCode debugging, event log will dump to syslog when driver detect uCode error occurred, but this only happen when compile with CONFIG_IWLWIFI_DEBUG and debug flag is enabled; which is not always the case. Also, there is another problem, if the flag is set, the entire event log buffer will be dump to syslog, it can flood the syslog and make it very difficult to debug the problem. Change the default to only dump last 20 entries of event log to syslog unless the following condition meets: 1. both compile with CONFIG_IWLWIFI_DEBUG and debug flag is enabled, and then dump the entire event buffer to syslog. 2. dump event log request from debugfs Signed-off-by: Wey-Yi Guy Acked-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 76 +++++++++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-core.c | 5 +- drivers/net/wireless/iwlwifi/iwl-core.h | 8 +-- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 74 +++++++++++++++++++++++----- 6 files changed, 130 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index a41f0e098cf6..ecc23ec1f6a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -227,7 +227,7 @@ extern void iwl3945_rx_replenish(void *data); extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr,int left); -extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv); +extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log); extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv); /* diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 927131192572..9b04b25f0e57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1696,8 +1696,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) } -#ifdef CONFIG_IWLWIFI_DEBUG - #define EVENT_START_OFFSET (4 * sizeof(u32)) /** @@ -1758,10 +1756,42 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } +/** + * iwl_print_last_event_logs - Dump the newest # of event log to syslog + */ +static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, + u32 num_wraps, u32 next_entry, + u32 size, u32 mode) +{ + /* + * display the newest DEFAULT_LOG_ENTRIES entries + * i.e the entries just before the next ont that uCode would fill. + */ + if (num_wraps) { + if (next_entry < size) { + iwl_print_event_log(priv, + capacity - (size - next_entry), + size - next_entry, mode); + iwl_print_event_log(priv, 0, + next_entry, mode); + } else + iwl_print_event_log(priv, next_entry - size, + size, mode); + } else { + if (next_entry < size) + iwl_print_event_log(priv, 0, next_entry, mode); + else + iwl_print_event_log(priv, next_entry - size, + size, mode); + } +} + /* For sanity check only. Actual size is determined by uCode, typ. 512 */ #define MAX_EVENT_LOG_SIZE (512) -void iwl_dump_nic_event_log(struct iwl_priv *priv) +#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) + +void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) { u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ @@ -1806,19 +1836,37 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) return; } - IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n", - size, num_wraps); - - /* if uCode has wrapped back to top of log, start at the oldest entry, - * i.e the next one that uCode would fill. */ - if (num_wraps) - iwl_print_event_log(priv, next_entry, - capacity - next_entry, mode); - /* (then/else) start at top of log */ - iwl_print_event_log(priv, 0, next_entry, mode); +#ifdef CONFIG_IWLWIFI_DEBUG + if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)) + size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; +#else + size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; +#endif + IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n", + size); -} +#ifdef CONFIG_IWLWIFI_DEBUG + if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { + /* + * if uCode has wrapped back to top of log, + * start at the oldest entry, + * i.e the next one that uCode would fill. + */ + if (num_wraps) + iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode); + /* (then/else) start at top of log */ + iwl_print_event_log(priv, 0, next_entry, mode); + } else + iwl_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); +#else + iwl_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); #endif +} /** * iwl_alive_start - called after REPLY_ALIVE notification received diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2e0fb2804ad0..3629aea250ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1362,11 +1362,10 @@ void iwl_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); priv->cfg->ops->lib->dump_nic_error_log(priv); + priv->cfg->ops->lib->dump_nic_event_log(priv, false); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) { - priv->cfg->ops->lib->dump_nic_event_log(priv); + if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) iwl_print_rx_config_cmd(priv); - } #endif wake_up_interruptible(&priv->wait_command_queue); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ecba0f46bac5..cf7d3df0744e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -167,7 +167,7 @@ struct iwl_lib_ops { int (*is_valid_rtc_data_addr)(u32 addr); /* 1st ucode load */ int (*load_ucode)(struct iwl_priv *priv); - void (*dump_nic_event_log)(struct iwl_priv *priv); + void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log); void (*dump_nic_error_log)(struct iwl_priv *priv); int (*set_channel_switch)(struct iwl_priv *priv, u16 channel); /* power management */ @@ -579,14 +579,10 @@ int iwl_pci_resume(struct pci_dev *pdev); * Error Handling Debugging ******************************************************/ void iwl_dump_nic_error_log(struct iwl_priv *priv); +void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log); #ifdef CONFIG_IWLWIFI_DEBUG -void iwl_dump_nic_event_log(struct iwl_priv *priv); void iwl_print_rx_config_cmd(struct iwl_priv *priv); #else -static inline void iwl_dump_nic_event_log(struct iwl_priv *priv) -{ -} - static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv) { } diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 5adf0b606202..21e0f6699daf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -436,7 +436,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, if (sscanf(buf, "%d", &event_log_flag) != 1) return -EFAULT; if (event_log_flag == 1) - priv->cfg->ops->lib->dump_nic_event_log(priv); + priv->cfg->ops->lib->dump_nic_event_log(priv, true); return count; } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5b7e80e5bab4..5e3c35314ffe 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1482,7 +1482,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) tasklet_kill(&priv->irq_tasklet); } -#ifdef CONFIG_IWLWIFI_DEBUG static const char *desc_lookup(int i) { switch (i) { @@ -1613,10 +1612,42 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } +/** + * iwl3945_print_last_event_logs - Dump the newest # of event log to syslog + */ +static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, + u32 num_wraps, u32 next_entry, + u32 size, u32 mode) +{ + /* + * display the newest DEFAULT_LOG_ENTRIES entries + * i.e the entries just before the next ont that uCode would fill. + */ + if (num_wraps) { + if (next_entry < size) { + iwl3945_print_event_log(priv, + capacity - (size - next_entry), + size - next_entry, mode); + iwl3945_print_event_log(priv, 0, + next_entry, mode); + } else + iwl3945_print_event_log(priv, next_entry - size, + size, mode); + } else { + if (next_entry < size) + iwl3945_print_event_log(priv, 0, next_entry, mode); + else + iwl3945_print_event_log(priv, next_entry - size, + size, mode); + } +} + /* For sanity check only. Actual size is determined by uCode, typ. 512 */ #define IWL3945_MAX_EVENT_LOG_SIZE (512) -void iwl3945_dump_nic_event_log(struct iwl_priv *priv) +#define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20) + +void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log) { u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ @@ -1657,8 +1688,17 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv) return; } - IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n", - size, num_wraps); +#ifdef CONFIG_IWLWIFI_DEBUG + if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)) + size = (size > DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES : size; +#else + size = (size > DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES : size; +#endif + + IWL_ERR(priv, "Start IWL Event Log Dump: display last %d count\n", + size); /* if uCode has wrapped back to top of log, start at the oldest entry, * i.e the next one that uCode would fill. */ @@ -1669,18 +1709,28 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv) /* (then/else) start at top of log */ iwl3945_print_event_log(priv, 0, next_entry, mode); -} +#ifdef CONFIG_IWLWIFI_DEBUG + if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { + /* if uCode has wrapped back to top of log, + * start at the oldest entry, + * i.e the next one that uCode would fill. + */ + if (num_wraps) + iwl3945_print_event_log(priv, next_entry, + capacity - next_entry, mode); + + /* (then/else) start at top of log */ + iwl3945_print_event_log(priv, 0, next_entry, mode); + } else + iwl3945_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); #else -void iwl3945_dump_nic_event_log(struct iwl_priv *priv) -{ -} + iwl3945_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); +#endif -void iwl3945_dump_nic_error_log(struct iwl_priv *priv) -{ } -#endif - static void iwl3945_irq_tasklet(struct iwl_priv *priv) { u32 inta, handled = 0; -- cgit v1.2.3 From 2d237f71b00bdc9044b5853d79f8cbef6c8df3ed Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:08 -0800 Subject: iwlwifi: change message for cmd queue full error Change error message for command queue full Signed-off-by: Wey-Yi Guy Acked-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index f3dff2ecc406..2eee950e0195 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1022,7 +1022,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) } if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { - IWL_ERR(priv, "No space for Tx\n"); + IWL_ERR(priv, "No space in command queue\n"); if (iwl_within_ct_kill_margin(priv)) iwl_tt_enter_ct_kill(priv); else { -- cgit v1.2.3 From 3681165235aae95a2e6d5407bb4e9426d68a37dd Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:09 -0800 Subject: iwlwifi: remove reset led_tpt from iwl_leds_init() Current blinking rate is calculated based on the difference between current tx/rx byte counts and priv->led_tpt. priv->led_tpt should not get reset in iwl_leds_init(), this function can be called by bring interface "up" or "down", or when uCode sysassert occurred. resetting the led_tpt parameter will introduce incorrect led blinking behavior. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-led.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 478c90511ebf..46c7a95b88f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -219,7 +219,6 @@ EXPORT_SYMBOL(iwl_leds_background); void iwl_leds_init(struct iwl_priv *priv) { priv->last_blink_rate = 0; - priv->led_tpt = 0; priv->last_blink_time = 0; priv->allow_blinking = 0; } -- cgit v1.2.3 From 827d42c9ac91ddd728e4f4a31fefb906ef2ceff7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 22 Nov 2009 12:28:41 +0100 Subject: mac80211: fix spurious delBA handling Lennert Buytenhek noticed that delBA handling in mac80211 was broken and has remotely triggerable problems, some of which are due to some code shuffling I did that ended up changing the order in which things were done -- this was commit d75636ef9c1af224f1097941879d5a8db7cd04e5 Author: Johannes Berg Date: Tue Feb 10 21:25:53 2009 +0100 mac80211: RX aggregation: clean up stop session and other parts were already present in the original commit d92684e66091c0f0101819619b315b4bb8b5bcc5 Author: Ron Rindjunsky Date: Mon Jan 28 14:07:22 2008 +0200 mac80211: A-MPDU Tx add delBA from recipient support The first problem is that I moved a BUG_ON before various checks -- thereby making it possible to hit. As the comment indicates, the BUG_ON can be removed since the ampdu_action callback must already exist when the state is != IDLE. The second problem isn't easily exploitable but there's a race condition due to unconditionally setting the state to OPERATIONAL when a delBA frame is received, even when no aggregation session was ever initiated. All the drivers accept stopping the session even then, but that opens a race window where crashes could happen before the driver accepts it. Right now, a WARN_ON may happen with non-HT drivers, while the race opens only for HT drivers. For this case, there are two things necessary to fix it: 1) don't process spurious delBA frames, and be more careful about the session state; don't drop the lock 2) HT drivers need to be prepared to handle a session stop even before the session was really started -- this is true for all drivers (that support aggregation) but iwlwifi which can be fixed easily. The other HT drivers (ath9k and ar9170) are behaving properly already. Reported-by: Lennert Buytenhek Cc: stable@kernel.org Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 10 +++++++++- include/net/mac80211.h | 6 ++++++ net/mac80211/agg-tx.c | 15 +++++++-------- net/mac80211/ht.c | 8 +++----- net/mac80211/ieee80211_i.h | 2 ++ 5 files changed, 27 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index fb9bcfa6d947..b7e196e3c8d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1277,8 +1277,16 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) return -ENXIO; } + if (priv->stations[sta_id].tid[tid].agg.state == + IWL_EMPTYING_HW_QUEUE_ADDBA) { + IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); + ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid); + priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; + return 0; + } + if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON) - IWL_WARN(priv, "Stopping AGG while state not IWL_AGG_ON\n"); + IWL_WARN(priv, "Stopping AGG while state not ON or starting\n"); tid_data = &priv->stations[sta_id].tid[tid]; ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c75b960c8ac8..998c30fc8981 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1283,6 +1283,12 @@ enum ieee80211_filter_flags { * * These flags are used with the ampdu_action() callback in * &struct ieee80211_ops to indicate which action is needed. + * + * Note that drivers MUST be able to deal with a TX aggregation + * session being stopped even before they OK'ed starting it by + * calling ieee80211_start_tx_ba_cb(_irqsafe), because the peer + * might receive the addBA frame and send a delBA right away! + * * @IEEE80211_AMPDU_RX_START: start Rx aggregation * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation * @IEEE80211_AMPDU_TX_START: start Tx aggregation diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 63224d1ee8dd..89e238b001de 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -123,13 +123,18 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 ieee80211_tx_skb(sdata, skb, 0); } -static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, - enum ieee80211_back_parties initiator) +int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, + enum ieee80211_back_parties initiator) { struct ieee80211_local *local = sta->local; int ret; u8 *state; +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", + sta->sta.addr, tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + state = &sta->ampdu_mlme.tid_state_tx[tid]; if (*state == HT_AGG_STATE_OPERATIONAL) @@ -143,7 +148,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, /* HW shall not deny going back to legacy */ if (WARN_ON(ret)) { - *state = HT_AGG_STATE_OPERATIONAL; /* * We may have pending packets get stuck in this case... * Not bothering with a workaround for now. @@ -525,11 +529,6 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, goto unlock; } -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", - sta->sta.addr, tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator); unlock: diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 48ef1a282b91..cdc58e61d921 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -141,7 +141,6 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_mgmt *mgmt, size_t len) { - struct ieee80211_local *local = sdata->local; u16 tid, params; u16 initiator; @@ -161,10 +160,9 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, WLAN_BACK_INITIATOR, 0); else { /* WLAN_BACK_RECIPIENT */ spin_lock_bh(&sta->lock); - sta->ampdu_mlme.tid_state_tx[tid] = - HT_AGG_STATE_OPERATIONAL; + if (sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK) + ___ieee80211_stop_tx_ba_session(sta, tid, + WLAN_BACK_RECIPIENT); spin_unlock_bh(&sta->lock); - ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, tid, - WLAN_BACK_RECIPIENT); } } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a910bf1f092f..10d316e455de 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1091,6 +1091,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, enum ieee80211_back_parties initiator); +int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, + enum ieee80211_back_parties initiator); /* Spectrum management */ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.3 From bd3709b546f0113b41f0ecceaf3452a073739bbc Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 2 Dec 2009 12:52:59 -0800 Subject: iwl3945: remove duplicated event logging code In the process of improving uCode event logging capability, the new implementation was introduced without removing the existing implementation. The event log will be dumped to dmesg twice. Remove the old implementation to only log the event once upon sys assert or request by user. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0db9b79a69a6..a63bd5ee53a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1701,15 +1701,6 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log) IWL_ERR(priv, "Start IWL Event Log Dump: display last %d count\n", size); - /* if uCode has wrapped back to top of log, start at the oldest entry, - * i.e the next one that uCode would fill. */ - if (num_wraps) - iwl3945_print_event_log(priv, next_entry, - capacity - next_entry, mode); - - /* (then/else) start at top of log */ - iwl3945_print_event_log(priv, 0, next_entry, mode); - #ifdef CONFIG_IWLWIFI_DEBUG if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { /* if uCode has wrapped back to top of log, -- cgit v1.2.3 From 212fb57519a65c8e15bd3f5db87c3328fcde88de Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 2 Dec 2009 12:53:00 -0800 Subject: iwlwifi: indicate uCode type when fail dump error/event log error_event_table_ptr is only set upon receipt of REPLY_ALIVE. Until then both event log and error log will fail. Add information to indicate which uCode encounter the failure case. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c96513bddb10..b8377efb3ba7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1662,7 +1662,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) 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); + IWL_ERR(priv, + "Not valid error log pointer 0x%08X for %s uCode\n", + base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); return; } @@ -1807,7 +1809,9 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) 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); + IWL_ERR(priv, + "Invalid event log pointer 0x%08X for %s uCode\n", + base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); return; } -- cgit v1.2.3 From 250cce26d5d03337aec4ff8405121f026adb4a89 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Wed, 2 Dec 2009 12:53:01 -0800 Subject: iwlwifi: driver version track kernel version The driver version number is a remnant from when there was an out-of-tree iwlwifi driver. Now that the driver forms part of kernel source we do not need a separate driver version. Instead, we now use the kernel version as driver version. We maintain the previous tags used to indicate which components the driver has been compiled with. Signed-off-by: Reinette Chatre Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.h | 4 +++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/iwlwifi') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index cf7d3df0744e..675b7df632fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -63,6 +63,8 @@ #ifndef __iwl_core_h__ #define __iwl_core_h__ +#include + /************************ * forward declarations * ************************/ @@ -70,7 +72,7 @@ struct iwl_host_cmd; struct iwl_cmd; -#define IWLWIFI_VERSION "1.3.27k" +#define IWLWIFI_VERSION UTS_RELEASE "-k" #define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation" #define DRV_AUTHOR "" diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a63bd5ee53a7..2a28a1f8b1fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -76,11 +76,9 @@ #define VS #endif -#define IWL39_VERSION "1.2.26k" VD VS +#define DRV_VERSION IWLWIFI_VERSION VD VS #define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation" #define DRV_AUTHOR "" -#define DRV_VERSION IWL39_VERSION - MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); -- cgit v1.2.3