diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-6000.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 48 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 5 |
6 files changed, 52 insertions, 10 deletions
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 = { | |||
490 | .supports_idle = true, | 490 | .supports_idle = true, |
491 | .adv_thermal_throttle = true, | 491 | .adv_thermal_throttle = true, |
492 | .support_ct_kill_exit = true, | 492 | .support_ct_kill_exit = true, |
493 | .support_sm_ps = true, | ||
493 | }; | 494 | }; |
494 | 495 | ||
495 | struct iwl_cfg iwl6050_2abg_cfg = { | 496 | struct iwl_cfg iwl6050_2abg_cfg = { |
@@ -579,6 +580,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { | |||
579 | .supports_idle = true, | 580 | .supports_idle = true, |
580 | .adv_thermal_throttle = true, | 581 | .adv_thermal_throttle = true, |
581 | .support_ct_kill_exit = true, | 582 | .support_ct_kill_exit = true, |
583 | .support_sm_ps = true, | ||
582 | }; | 584 | }; |
583 | 585 | ||
584 | MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); | 586 | 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) | |||
3011 | priv->band = IEEE80211_BAND_2GHZ; | 3011 | priv->band = IEEE80211_BAND_2GHZ; |
3012 | 3012 | ||
3013 | priv->iw_mode = NL80211_IFTYPE_STATION; | 3013 | priv->iw_mode = NL80211_IFTYPE_STATION; |
3014 | if (priv->cfg->support_sm_ps) | ||
3015 | priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DYNAMIC; | ||
3016 | else | ||
3017 | priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; | ||
3014 | 3018 | ||
3015 | /* Choose which receivers/antennas to use */ | 3019 | /* Choose which receivers/antennas to use */ |
3016 | if (priv->cfg->ops->hcmd->set_rxon_chain) | 3020 | 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, | |||
414 | if (priv->cfg->ht_greenfield_support) | 414 | if (priv->cfg->ht_greenfield_support) |
415 | ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; | 415 | ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; |
416 | ht_info->cap |= IEEE80211_HT_CAP_SGI_20; | 416 | ht_info->cap |= IEEE80211_HT_CAP_SGI_20; |
417 | ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & | 417 | if (priv->cfg->support_sm_ps) |
418 | (WLAN_HT_CAP_SM_PS_DISABLED << 2)); | 418 | ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & |
419 | (WLAN_HT_CAP_SM_PS_DYNAMIC << 2)); | ||
420 | else | ||
421 | ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & | ||
422 | (WLAN_HT_CAP_SM_PS_DISABLED << 2)); | ||
419 | 423 | ||
420 | max_bit_rate = MAX_BIT_RATE_20_MHZ; | 424 | max_bit_rate = MAX_BIT_RATE_20_MHZ; |
421 | if (priv->hw_params.ht40_channel & BIT(band)) { | 425 | if (priv->hw_params.ht40_channel & BIT(band)) { |
@@ -963,17 +967,35 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) | |||
963 | } | 967 | } |
964 | 968 | ||
965 | /* | 969 | /* |
966 | * When we are in power saving, there's no difference between | 970 | * When we are in power saving mode, unless device support spatial |
967 | * using multiple chains or just a single chain, but due to the | 971 | * multiplexing power save, use the active count for rx chain count. |
968 | * lack of SM PS we lose a lot of throughput if we use just a | ||
969 | * single chain. | ||
970 | * | ||
971 | * Therefore, use the active count here (which will use multiple | ||
972 | * chains unless connected to a legacy AP). | ||
973 | */ | 972 | */ |
974 | static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) | 973 | static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) |
975 | { | 974 | { |
976 | return active_cnt; | 975 | int idle_cnt = active_cnt; |
976 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); | ||
977 | |||
978 | if (priv->cfg->support_sm_ps) { | ||
979 | /* # Rx chains when idling and maybe trying to save power */ | ||
980 | switch (priv->current_ht_config.sm_ps) { | ||
981 | case WLAN_HT_CAP_SM_PS_STATIC: | ||
982 | case WLAN_HT_CAP_SM_PS_DYNAMIC: | ||
983 | idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : | ||
984 | IWL_NUM_IDLE_CHAINS_SINGLE; | ||
985 | break; | ||
986 | case WLAN_HT_CAP_SM_PS_DISABLED: | ||
987 | idle_cnt = (is_cam) ? active_cnt : | ||
988 | IWL_NUM_IDLE_CHAINS_SINGLE; | ||
989 | break; | ||
990 | case WLAN_HT_CAP_SM_PS_INVALID: | ||
991 | default: | ||
992 | IWL_ERR(priv, "invalid sm_ps mode %d\n", | ||
993 | priv->current_ht_config.sm_ps); | ||
994 | WARN_ON(1); | ||
995 | break; | ||
996 | } | ||
997 | } | ||
998 | return idle_cnt; | ||
977 | } | 999 | } |
978 | 1000 | ||
979 | /* up to 4 chains */ | 1001 | /* up to 4 chains */ |
@@ -2257,6 +2279,12 @@ static void iwl_ht_conf(struct iwl_priv *priv, | |||
2257 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; | 2279 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; |
2258 | maxstreams += 1; | 2280 | maxstreams += 1; |
2259 | 2281 | ||
2282 | ht_conf->sm_ps = | ||
2283 | (u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS) | ||
2284 | >> 2); | ||
2285 | IWL_DEBUG_MAC80211(priv, "sm_ps: 0x%x\n", | ||
2286 | ht_conf->sm_ps); | ||
2287 | |||
2260 | if ((ht_cap->mcs.rx_mask[1] == 0) && | 2288 | if ((ht_cap->mcs.rx_mask[1] == 0) && |
2261 | (ht_cap->mcs.rx_mask[2] == 0)) | 2289 | (ht_cap->mcs.rx_mask[2] == 0)) |
2262 | ht_conf->single_chain_sufficient = true; | 2290 | 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 { | |||
228 | * @chain_noise_num_beacons: number of beacons used to compute chain noise | 228 | * @chain_noise_num_beacons: number of beacons used to compute chain noise |
229 | * @adv_thermal_throttle: support advance thermal throttle | 229 | * @adv_thermal_throttle: support advance thermal throttle |
230 | * @support_ct_kill_exit: support ct kill exit condition | 230 | * @support_ct_kill_exit: support ct kill exit condition |
231 | * @support_sm_ps: support spatial multiplexing power save | ||
231 | * | 232 | * |
232 | * We enable the driver to be backward compatible wrt API version. The | 233 | * We enable the driver to be backward compatible wrt API version. The |
233 | * driver specifies which APIs it supports (with @ucode_api_max being the | 234 | * driver specifies which APIs it supports (with @ucode_api_max being the |
@@ -283,6 +284,7 @@ struct iwl_cfg { | |||
283 | const bool supports_idle; | 284 | const bool supports_idle; |
284 | bool adv_thermal_throttle; | 285 | bool adv_thermal_throttle; |
285 | bool support_ct_kill_exit; | 286 | bool support_ct_kill_exit; |
287 | bool support_sm_ps; | ||
286 | }; | 288 | }; |
287 | 289 | ||
288 | /*************************** | 290 | /*************************** |
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 { | |||
517 | bool is_ht; | 517 | bool is_ht; |
518 | bool is_40mhz; | 518 | bool is_40mhz; |
519 | bool single_chain_sufficient; | 519 | bool single_chain_sufficient; |
520 | u8 sm_ps; | ||
520 | /* BSS related data */ | 521 | /* BSS related data */ |
521 | u8 extension_chan_offset; | 522 | u8 extension_chan_offset; |
522 | u8 ht_protection; | 523 | 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, | |||
182 | goto done; | 182 | goto done; |
183 | 183 | ||
184 | mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; | 184 | mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; |
185 | IWL_DEBUG_ASSOC(priv, "spatial multiplexing power save mode: %s\n", | ||
186 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? | ||
187 | "static" : | ||
188 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? | ||
189 | "dynamic" : "disabled"); | ||
185 | 190 | ||
186 | sta_flags = priv->stations[index].sta.station_flags; | 191 | sta_flags = priv->stations[index].sta.station_flags; |
187 | 192 | ||