aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorDaniel C Halperin <daniel.c.halperin@intel.com>2009-08-28 12:44:46 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-31 14:42:09 -0400
commitb58ef214b7db57cfcbca0e1edae08566cdfd56b7 (patch)
tree9bc6b75082a19eee04118fd1a23759d772e9e027 /drivers/net/wireless
parent5027309b5581e9c251a46f0ecbf88996d5e0f1e0 (diff)
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: Daniel C Halperin <daniel.c.halperin@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c111
1 files changed, 62 insertions, 49 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 7bc9c0039f79..a7422e52d883 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -566,62 +566,81 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
566static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, 566static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
567 struct iwl_tx_cmd *tx_cmd, 567 struct iwl_tx_cmd *tx_cmd,
568 struct ieee80211_tx_info *info, 568 struct ieee80211_tx_info *info,
569 __le16 fc, int sta_id, 569 __le16 fc, int is_hcca)
570 int is_hcca)
571{ 570{
572 u32 rate_flags = 0; 571 u32 rate_flags;
573 int rate_idx; 572 int rate_idx;
574 u8 rts_retry_limit = 0; 573 u8 rts_retry_limit;
575 u8 data_retry_limit = 0; 574 u8 data_retry_limit;
576 u8 rate_plcp; 575 u8 rate_plcp;
577 576
578 rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff, 577 /* Set retry limit on DATA packets and Probe Responses*/
579 IWL_RATE_COUNT - 1);
580
581 rate_plcp = iwl_rates[rate_idx].plcp;
582
583 rts_retry_limit = (is_hcca) ?
584 RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
585
586 if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
587 rate_flags |= RATE_MCS_CCK_MSK;
588
589
590 if (ieee80211_is_probe_resp(fc)) {
591 data_retry_limit = 3;
592 if (data_retry_limit < rts_retry_limit)
593 rts_retry_limit = data_retry_limit;
594 } else
595 data_retry_limit = IWL_DEFAULT_TX_RETRY;
596
597 if (priv->data_retry_limit != -1) 578 if (priv->data_retry_limit != -1)
598 data_retry_limit = priv->data_retry_limit; 579 data_retry_limit = priv->data_retry_limit;
580 else if (ieee80211_is_probe_resp(fc))
581 data_retry_limit = 3;
582 else
583 data_retry_limit = IWL_DEFAULT_TX_RETRY;
584 tx_cmd->data_retry_limit = data_retry_limit;
599 585
586 /* Set retry limit on RTS packets */
587 rts_retry_limit = (is_hcca) ? RTS_HCCA_RETRY_LIMIT :
588 RTS_DFAULT_RETRY_LIMIT;
589 if (data_retry_limit < rts_retry_limit)
590 rts_retry_limit = data_retry_limit;
591 tx_cmd->rts_retry_limit = rts_retry_limit;
600 592
593 /* DATA packets will use the uCode station table for rate/antenna
594 * selection */
601 if (ieee80211_is_data(fc)) { 595 if (ieee80211_is_data(fc)) {
602 tx_cmd->initial_rate_index = 0; 596 tx_cmd->initial_rate_index = 0;
603 tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; 597 tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
604 } else { 598 return;
605 switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { 599 }
606 case cpu_to_le16(IEEE80211_STYPE_AUTH): 600
607 case cpu_to_le16(IEEE80211_STYPE_DEAUTH): 601 /**
608 case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): 602 * If the current TX rate stored in mac80211 has the MCS bit set, it's
609 case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): 603 * not really a TX rate. Thus, we use the lowest supported rate for
610 if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) { 604 * this band. Also use the lowest supported rate if the stored rate
611 tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK; 605 * index is invalid.
612 tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK; 606 */
613 } 607 rate_idx = info->control.rates[0].idx;
614 break; 608 if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
615 default: 609 (rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
616 break; 610 rate_idx = rate_lowest_index(&priv->bands[info->band],
617 } 611 info->control.sta);
612 /* For 5 GHZ band, remap mac80211 rate indices into driver indices */
613 if (info->band == IEEE80211_BAND_5GHZ)
614 rate_idx += IWL_FIRST_OFDM_RATE;
615 /* Get PLCP rate for tx_cmd->rate_n_flags */
616 rate_plcp = iwl_rates[rate_idx].plcp;
617 /* Zero out flags for this packet */
618 rate_flags = 0;
618 619
619 priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); 620 /* Set CCK flag as needed */
620 rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); 621 if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
622 rate_flags |= RATE_MCS_CCK_MSK;
623
624 /* Set up RTS and CTS flags for certain packets */
625 switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
626 case cpu_to_le16(IEEE80211_STYPE_AUTH):
627 case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
628 case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
629 case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
630 if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
631 tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
632 tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
633 }
634 break;
635 default:
636 break;
621 } 637 }
622 638
623 tx_cmd->rts_retry_limit = rts_retry_limit; 639 /* Set up antennas */
624 tx_cmd->data_retry_limit = data_retry_limit; 640 priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
641 rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
642
643 /* Set the rate in the TX cmd */
625 tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags); 644 tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags);
626} 645}
627 646
@@ -701,12 +720,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
701 goto drop_unlock; 720 goto drop_unlock;
702 } 721 }
703 722
704 if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) ==
705 IWL_INVALID_RATE) {
706 IWL_ERR(priv, "ERROR: No TX rate available.\n");
707 goto drop_unlock;
708 }
709
710 fc = hdr->frame_control; 723 fc = hdr->frame_control;
711 724
712#ifdef CONFIG_IWLWIFI_DEBUG 725#ifdef CONFIG_IWLWIFI_DEBUG
@@ -807,7 +820,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
807 iwl_dbg_log_tx_data_frame(priv, len, hdr); 820 iwl_dbg_log_tx_data_frame(priv, len, hdr);
808 821
809 /* set is_hcca to 0; it probably will never be implemented */ 822 /* set is_hcca to 0; it probably will never be implemented */
810 iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); 823 iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, 0);
811 824
812 iwl_update_stats(priv, true, fc, len); 825 iwl_update_stats(priv, true, fc, len);
813 /* 826 /*