|
@@ -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");
|
|
|
}
|