Commit b58ef214 authored by Daniel C Halperin's avatar Daniel C Halperin Committed by John W. Linville

iwlwifi: remove incorrect uses of ieee80211_get_tx_rate to prevent TX stall

Refactor and correct rate selection for outgoing transmitted
packets.

First, note that HT rates in the mac80211 rate table do not provide valid
indices when ieee80211_get_tx_rate is called; the check to see if we could to
abort a transmission early in iwl_tx_skb() would thus occasionally read invalid
memory and occasionally stall transmission (if the erroneous byte was 0xff).
We remove that code; the check wasn't valid anyway.

Second, iwl_tx_cmd_build_rate() also called ieee80211_get_tx_rate to be used
for sending management packets, which do not use the uCode station table.  This
patch refactors that function and adds comments to enhance legibility, replaces
the call to ieee80211_get_tx_rate() with a direct lookup, and adds error
handling in case the table entry is invalid.
Signed-off-by: default avatarDaniel C Halperin <daniel.c.halperin@intel.com>
Signed-off-by: default avatarReinette Chatre <reinette.chatre@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 5027309b
...@@ -566,42 +566,62 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, ...@@ -566,42 +566,62 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
struct iwl_tx_cmd *tx_cmd, struct iwl_tx_cmd *tx_cmd,
struct ieee80211_tx_info *info, struct ieee80211_tx_info *info,
__le16 fc, int sta_id, __le16 fc, int is_hcca)
int is_hcca)
{ {
u32 rate_flags = 0; u32 rate_flags;
int rate_idx; int rate_idx;
u8 rts_retry_limit = 0; u8 rts_retry_limit;
u8 data_retry_limit = 0; u8 data_retry_limit;
u8 rate_plcp; u8 rate_plcp;
rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff, /* Set retry limit on DATA packets and Probe Responses*/
IWL_RATE_COUNT - 1);
rate_plcp = iwl_rates[rate_idx].plcp;
rts_retry_limit = (is_hcca) ?
RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
rate_flags |= RATE_MCS_CCK_MSK;
if (ieee80211_is_probe_resp(fc)) {
data_retry_limit = 3;
if (data_retry_limit < rts_retry_limit)
rts_retry_limit = data_retry_limit;
} else
data_retry_limit = IWL_DEFAULT_TX_RETRY;
if (priv->data_retry_limit != -1) if (priv->data_retry_limit != -1)
data_retry_limit = priv->data_retry_limit; data_retry_limit = priv->data_retry_limit;
else if (ieee80211_is_probe_resp(fc))
data_retry_limit = 3;
else
data_retry_limit = IWL_DEFAULT_TX_RETRY;
tx_cmd->data_retry_limit = data_retry_limit;
/* Set retry limit on RTS packets */
rts_retry_limit = (is_hcca) ? RTS_HCCA_RETRY_LIMIT :
RTS_DFAULT_RETRY_LIMIT;
if (data_retry_limit < rts_retry_limit)
rts_retry_limit = data_retry_limit;
tx_cmd->rts_retry_limit = rts_retry_limit;
/* DATA packets will use the uCode station table for rate/antenna
* selection */
if (ieee80211_is_data(fc)) { if (ieee80211_is_data(fc)) {
tx_cmd->initial_rate_index = 0; tx_cmd->initial_rate_index = 0;
tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
} else { return;
}
/**
* If the current TX rate stored in mac80211 has the MCS bit set, it's
* not really a TX rate. Thus, we use the lowest supported rate for
* this band. Also use the lowest supported rate if the stored rate
* index is invalid.
*/
rate_idx = info->control.rates[0].idx;
if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
(rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
rate_idx = rate_lowest_index(&priv->bands[info->band],
info->control.sta);
/* For 5 GHZ band, remap mac80211 rate indices into driver indices */
if (info->band == IEEE80211_BAND_5GHZ)
rate_idx += IWL_FIRST_OFDM_RATE;
/* Get PLCP rate for tx_cmd->rate_n_flags */
rate_plcp = iwl_rates[rate_idx].plcp;
/* Zero out flags for this packet */
rate_flags = 0;
/* Set CCK flag as needed */
if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
rate_flags |= RATE_MCS_CCK_MSK;
/* Set up RTS and CTS flags for certain packets */
switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
case cpu_to_le16(IEEE80211_STYPE_AUTH): case cpu_to_le16(IEEE80211_STYPE_AUTH):
case cpu_to_le16(IEEE80211_STYPE_DEAUTH): case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
...@@ -616,12 +636,11 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, ...@@ -616,12 +636,11 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
break; break;
} }
/* Set up antennas */
priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
}
tx_cmd->rts_retry_limit = rts_retry_limit; /* Set the rate in the TX cmd */
tx_cmd->data_retry_limit = data_retry_limit;
tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags); tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags);
} }
...@@ -701,12 +720,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) ...@@ -701,12 +720,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
goto drop_unlock; goto drop_unlock;
} }
if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) ==
IWL_INVALID_RATE) {
IWL_ERR(priv, "ERROR: No TX rate available.\n");
goto drop_unlock;
}
fc = hdr->frame_control; fc = hdr->frame_control;
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
...@@ -807,7 +820,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) ...@@ -807,7 +820,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
iwl_dbg_log_tx_data_frame(priv, len, hdr); iwl_dbg_log_tx_data_frame(priv, len, hdr);
/* set is_hcca to 0; it probably will never be implemented */ /* set is_hcca to 0; it probably will never be implemented */
iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, 0);
iwl_update_stats(priv, true, fc, len); iwl_update_stats(priv, true, fc, len);
/* /*
......
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