Commit 28a6b07a authored by Tomas Winkler's avatar Tomas Winkler Committed by John W. Linville

iwlwifi: fix rx_chain computation

This patch fixes rx_chain computation. The code that adjusts number of
rx chains to number supported by HW was missing. Miss configuration
causes firmware error.  Note: iwlwifi supports HW with up to 3 RX
chains (2x2, 2x3, 1x2, and 3x3 MIMO). This patch also simplifies the
whole RX chain computation.
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarMohamed Abbas <mohamed.abbas@intel.com>
Signed-off-by: default avatarZhu Yi <yi.zhu@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 4834c73f
...@@ -592,12 +592,11 @@ static void iwlcore_free_geos(struct iwl_priv *priv) ...@@ -592,12 +592,11 @@ static void iwlcore_free_geos(struct iwl_priv *priv)
clear_bit(STATUS_GEO_CONFIGURED, &priv->status); clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
} }
static u8 is_single_rx_stream(struct iwl_priv *priv) static bool is_single_rx_stream(struct iwl_priv *priv)
{ {
return !priv->current_ht_config.is_ht || return !priv->current_ht_config.is_ht ||
((priv->current_ht_config.supp_mcs_set[1] == 0) && ((priv->current_ht_config.supp_mcs_set[1] == 0) &&
(priv->current_ht_config.supp_mcs_set[2] == 0)) || (priv->current_ht_config.supp_mcs_set[2] == 0));
priv->ps_mode == IWL_MIMO_PS_STATIC;
} }
static u8 iwl_is_channel_extension(struct iwl_priv *priv, static u8 iwl_is_channel_extension(struct iwl_priv *priv,
...@@ -704,33 +703,39 @@ EXPORT_SYMBOL(iwl_set_rxon_ht); ...@@ -704,33 +703,39 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
* MIMO (dual stream) requires at least 2, but works better with 3. * MIMO (dual stream) requires at least 2, but works better with 3.
* This does not determine *which* chains to use, just how many. * This does not determine *which* chains to use, just how many.
*/ */
static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv, static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
u8 *idle_state, u8 *rx_state)
{ {
u8 is_single = is_single_rx_stream(priv); bool is_single = is_single_rx_stream(priv);
u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1; bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
/* # of Rx chains to use when expecting MIMO. */ /* # of Rx chains to use when expecting MIMO. */
if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
*rx_state = 2; return 2;
else else
*rx_state = 3; return 3;
}
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 */ /* # Rx chains when idling and maybe trying to save power */
switch (priv->ps_mode) { switch (priv->ps_mode) {
case IWL_MIMO_PS_STATIC: case IWL_MIMO_PS_STATIC:
case IWL_MIMO_PS_DYNAMIC: case IWL_MIMO_PS_DYNAMIC:
*idle_state = (is_cam) ? 2 : 1; idle_cnt = (is_cam) ? 2 : 1;
break; break;
case IWL_MIMO_PS_NONE: case IWL_MIMO_PS_NONE:
*idle_state = (is_cam) ? *rx_state : 1; idle_cnt = (is_cam) ? active_cnt : 1;
break; break;
case IWL_MIMO_PS_INVALID:
default: default:
*idle_state = 1; IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode);
WARN_ON(1);
idle_cnt = -1;
break; break;
} }
return idle_cnt;
return 0;
} }
/** /**
...@@ -741,34 +746,44 @@ static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv, ...@@ -741,34 +746,44 @@ static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
*/ */
void iwl_set_rxon_chain(struct iwl_priv *priv) void iwl_set_rxon_chain(struct iwl_priv *priv)
{ {
u8 is_single = is_single_rx_stream(priv); bool is_single = is_single_rx_stream(priv);
u8 idle_state, rx_state; bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
u8 idle_rx_cnt, active_rx_cnt;
priv->staging_rxon.rx_chain = 0; u16 rx_chain;
rx_state = idle_state = 3;
/* Tell uCode which antennas are actually connected. /* Tell uCode which antennas are actually connected.
* Before first association, we assume all antennas are connected. * Before first association, we assume all antennas are connected.
* Just after first association, iwl_chain_noise_calibration() * Just after first association, iwl_chain_noise_calibration()
* checks which antennas actually *are* connected. */ * checks which antennas actually *are* connected. */
priv->staging_rxon.rx_chain |= rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
cpu_to_le16(priv->hw_params.valid_rx_ant <<
RXON_RX_CHAIN_VALID_POS);
/* How many receivers should we use? */ /* How many receivers should we use? */
iwlcore_get_rx_chain_counter(priv, &idle_state, &rx_state); active_rx_cnt = iwl_get_active_rx_chain_count(priv);
priv->staging_rxon.rx_chain |= idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
priv->staging_rxon.rx_chain |= /* correct rx chain count accoridng hw settings */
cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS); if (priv->hw_params.rx_chains_num < active_rx_cnt)
active_rx_cnt = priv->hw_params.rx_chains_num;
if (!is_single && (rx_state >= 2) &&
!test_bit(STATUS_POWER_PMI, &priv->status)) if (priv->hw_params.rx_chains_num < idle_rx_cnt)
idle_rx_cnt = priv->hw_params.rx_chains_num;
rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS;
priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
if (!is_single && (active_rx_cnt >= 2) && is_cam)
priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
else else
priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n",
priv->staging_rxon.rx_chain,
active_rx_cnt, idle_rx_cnt);
WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
active_rx_cnt < idle_rx_cnt);
} }
EXPORT_SYMBOL(iwl_set_rxon_chain); EXPORT_SYMBOL(iwl_set_rxon_chain);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment