ath9k: Handle mac80211's RC flags for MCS rates
authorSujith <Sujith.Manoharan@atheros.com>
Fri, 30 Jan 2009 08:59:28 +0000 (14:29 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 9 Feb 2009 20:03:44 +0000 (15:03 -0500)
mac80211 notifies the RC algorithm if RTS/CTS and short preamble
are needed. The RC flags for MCS rates are currently not handled
by mac80211, and ath9k's RC doesn't set the flags either. Fix this.

Also, set the rts_cts_rate_idx inside the RC algorithm.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath9k/core.h
drivers/net/wireless/ath9k/mac.c
drivers/net/wireless/ath9k/rc.c
drivers/net/wireless/ath9k/xmit.c

index 9a7bb1b5cd51feddc2d95602f1005a1adabd17a1..8683fc8ddb3c549ea2f71a99455c8e37e2bf221c 100644 (file)
@@ -233,7 +233,6 @@ struct ath_buf_state {
 #define bf_isht(bf)            (bf->bf_state.bf_type & BUF_HT)
 #define bf_isretried(bf)       (bf->bf_state.bf_type & BUF_RETRY)
 #define bf_isxretried(bf)      (bf->bf_state.bf_type & BUF_XRETRY)
-#define bf_isshpreamble(bf)    (bf->bf_state.bf_type & BUF_SHORT_PREAMBLE)
 #define bf_isbar(bf)           (bf->bf_state.bf_type & BUF_BAR)
 #define bf_ispspoll(bf)        (bf->bf_state.bf_type & BUF_PSPOLL)
 #define bf_isaggrburst(bf)     (bf->bf_state.bf_type & BUF_AGGR_BURST)
@@ -658,12 +657,6 @@ struct ath_rfkill {
 #define ATH_RSSI_DUMMY_MARKER   0x127
 #define ATH_RATE_DUMMY_MARKER   0
 
-enum PROT_MODE {
-       PROT_M_NONE = 0,
-       PROT_M_RTSCTS,
-       PROT_M_CTSONLY
-};
-
 #define SC_OP_INVALID          BIT(0)
 #define SC_OP_BEACONS          BIT(1)
 #define SC_OP_RXAGGR           BIT(2)
@@ -715,7 +708,6 @@ struct ath_softc {
        u8 sc_splitmic;
        atomic_t ps_usecount;
        enum ath9k_int sc_imask;
-       enum PROT_MODE sc_protmode;
        enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
        enum ath9k_ht_macmode tx_chan_width;
 
index ef832a5ebbd8f2d6b86f9d473a8aa27df5e030ea..2427c44a8c35cd1fc0960e8f06fc24ddaa339d5a 100644 (file)
@@ -344,9 +344,6 @@ void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
        struct ar5416_desc *last_ads = AR5416DESC(lastds);
        u32 ds_ctl0;
 
-       (void) nseries;
-       (void) rtsctsDuration;
-
        if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
                ds_ctl0 = ads->ds_ctl0;
 
index 8bc7bb50c7fc6aba8f21aad54aa7fa79180fa76d..a8c4f9757eb10f674728908608bb11d5066034db 100644 (file)
@@ -747,14 +747,17 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
        return rate;
 }
 
-static void ath_rc_rate_set_series(struct ath_rate_table *rate_table ,
+static void ath_rc_rate_set_series(struct ath_rate_table *rate_table,
                                   struct ieee80211_tx_rate *rate,
+                                  struct ieee80211_tx_rate_control *txrc,
                                   u8 tries, u8 rix, int rtsctsenable)
 {
        rate->count = tries;
        rate->idx = rix;
 
-       if (rtsctsenable)
+       if (txrc->short_preamble)
+               rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
+       if (txrc->rts || rtsctsenable)
                rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
        if (WLAN_RC_PHY_40(rate_table->info[rix].phy))
                rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
@@ -764,6 +767,43 @@ static void ath_rc_rate_set_series(struct ath_rate_table *rate_table ,
                rate->flags |= IEEE80211_TX_RC_MCS;
 }
 
+static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
+                                  struct ath_rate_table *rate_table,
+                                  struct ieee80211_tx_info *tx_info)
+{
+       struct ieee80211_tx_rate *rates = tx_info->control.rates;
+       int i = 0, rix = 0, cix, enable_g_protection = 0;
+
+       /* get the cix for the lowest valid rix */
+       for (i = 3; i >= 0; i--) {
+               if (rates[i].count && (rates[i].idx >= 0)) {
+                       rix = rates[i].idx;
+                       break;
+               }
+       }
+       cix = rate_table->info[rix].ctrl_rate;
+
+       /* All protection frames are transmited at 2Mb/s for 802.11g,
+        * otherwise we transmit them at 1Mb/s */
+       if (sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ &&
+           !conf_is_ht(&sc->hw->conf))
+               enable_g_protection = 1;
+
+       /*
+        * If 802.11g protection is enabled, determine whether to use RTS/CTS or
+        * just CTS.  Note that this is only done for OFDM/HT unicast frames.
+        */
+       if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) &&
+           !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+           (rate_table->info[rix].phy == WLAN_RC_PHY_OFDM ||
+            WLAN_RC_PHY_HT(rate_table->info[rix].phy))) {
+               rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT;
+               cix = rate_table->info[enable_g_protection].ctrl_rate;
+       }
+
+       tx_info->control.rts_cts_rate_idx = cix;
+}
+
 static u8 ath_rc_rate_getidx(struct ath_softc *sc,
                             struct ath_rate_priv *ath_rc_priv,
                             struct ath_rate_table *rate_table,
@@ -801,6 +841,8 @@ static void ath_rc_ratefind(struct ath_softc *sc,
        struct sk_buff *skb = txrc->skb;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_tx_rate *rates = tx_info->control.rates;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       __le16 fc = hdr->frame_control;
        u8 try_per_rate = 0, i = 0, rix, nrix;
        int is_probe = 0;
 
@@ -811,7 +853,7 @@ static void ath_rc_ratefind(struct ath_softc *sc,
        if (is_probe) {
                /* set one try for probe rates. For the
                 * probes don't enable rts */
-               ath_rc_rate_set_series(rate_table, &rates[i++],
+               ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
                                       1, nrix, 0);
 
                try_per_rate = (ATH_11N_TXMAXTRY/4);
@@ -820,12 +862,12 @@ static void ath_rc_ratefind(struct ath_softc *sc,
                 */
                nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
                                          rate_table, nrix, 1, 0);
-               ath_rc_rate_set_series(rate_table, &rates[i++],
+               ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
                                       try_per_rate, nrix, 0);
        } else {
                try_per_rate = (ATH_11N_TXMAXTRY/4);
                /* Set the choosen rate. No RTS for first series entry. */
-               ath_rc_rate_set_series(rate_table, &rates[i++],
+               ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
                                       try_per_rate, nrix, 0);
        }
 
@@ -841,7 +883,7 @@ static void ath_rc_ratefind(struct ath_softc *sc,
                nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
                                          rate_table, nrix, 1, min_rate);
                /* All other rates in the series have RTS enabled */
-               ath_rc_rate_set_series(rate_table, &rates[i],
+               ath_rc_rate_set_series(rate_table, &rates[i], txrc,
                                       try_num, nrix, 1);
        }
 
@@ -871,6 +913,24 @@ static void ath_rc_ratefind(struct ath_softc *sc,
                        rates[3].flags = rates[2].flags;
                }
        }
+
+       /*
+        * Force hardware to use computed duration for next
+        * fragment by disabling multi-rate retry, which
+        * updates duration based on the multi-rate duration table.
+        *
+        * FIXME: Fix duration
+        */
+       if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+           (ieee80211_has_morefrags(fc) ||
+            (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG))) {
+               rates[1].count = rates[2].count = rates[3].count = 0;
+               rates[1].idx = rates[2].idx = rates[3].idx = 0;
+               rates[0].count = ATH_TXMAXTRY;
+       }
+
+       /* Setup RTS/CTS */
+       ath_rc_rate_set_rtscts(sc, rate_table, tx_info);
 }
 
 static bool ath_rc_update_per(struct ath_softc *sc,
@@ -1385,16 +1445,16 @@ static void ath_rc_init(struct ath_softc *sc,
        if (!rateset->rs_nrates) {
                /* No working rate, just initialize valid rates */
                hi = ath_rc_init_validrates(ath_rc_priv, rate_table,
-                                               ath_rc_priv->ht_cap);
+                                           ath_rc_priv->ht_cap);
        } else {
                /* Use intersection of working rates and valid rates */
                hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table,
-                                              rateset, ath_rc_priv->ht_cap);
+                                          rateset, ath_rc_priv->ht_cap);
                if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) {
                        hthi = ath_rc_setvalid_htrates(ath_rc_priv,
-                                                          rate_table,
-                                                          ht_mcs,
-                                                          ath_rc_priv->ht_cap);
+                                                      rate_table,
+                                                      ht_mcs,
+                                                      ath_rc_priv->ht_cap);
                }
                hi = A_MAX(hi, hthi);
        }
index d483f3c135011823305d2e5de8032cd977990a09..e14bceaef1252b12e04848cf22eddc8d00ee8ff7 100644 (file)
@@ -1386,8 +1386,6 @@ static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb,
 
        if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
                flags |= ATH9K_TXDESC_NOACK;
-       if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
-               flags |= ATH9K_TXDESC_RTSENA;
 
        return flags;
 }
@@ -1433,137 +1431,86 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
 
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
 {
-       struct ath_hal *ah = sc->sc_ah;
-       struct ath_rate_table *rt;
-       struct ath_desc *ds = bf->bf_desc;
-       struct ath_desc *lastds = bf->bf_lastbf->bf_desc;
+       struct ath_rate_table *rt = sc->cur_rate_table;
        struct ath9k_11n_rate_series series[4];
        struct sk_buff *skb;
        struct ieee80211_tx_info *tx_info;
        struct ieee80211_tx_rate *rates;
-       struct ieee80211_hdr *hdr;
-       struct ieee80211_hw *hw = sc->hw;
-       int i, flags, rtsctsena = 0, enable_g_protection = 0;
-       u32 ctsduration = 0;
-       u8 rix = 0, cix, ctsrate = 0;
-       __le16 fc;
+       int i, flags = 0;
+       u8 rix = 0, ctsrate = 0;
 
        memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
 
        skb = (struct sk_buff *)bf->bf_mpdu;
-       hdr = (struct ieee80211_hdr *)skb->data;
-       fc = hdr->frame_control;
        tx_info = IEEE80211_SKB_CB(skb);
        rates = tx_info->control.rates;
 
-       if (ieee80211_has_morefrags(fc) ||
-           (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
-               rates[1].count = rates[2].count = rates[3].count = 0;
-               rates[1].idx = rates[2].idx = rates[3].idx = 0;
-               rates[0].count = ATH_TXMAXTRY;
-       }
-
-       /* get the cix for the lowest valid rix */
-       rt = sc->cur_rate_table;
-       for (i = 3; i >= 0; i--) {
-               if (rates[i].count && (rates[i].idx >= 0)) {
-                       rix = rates[i].idx;
-                       break;
-               }
-       }
-
-       flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA));
-       cix = rt->info[rix].ctrl_rate;
-
-       /* All protection frames are transmited at 2Mb/s for 802.11g,
-        * otherwise we transmit them at 1Mb/s */
-       if (hw->conf.channel->band == IEEE80211_BAND_2GHZ &&
-         !conf_is_ht(&hw->conf))
-               enable_g_protection = 1;
-
        /*
-        * If 802.11g protection is enabled, determine whether to use RTS/CTS or
-        * just CTS.  Note that this is only done for OFDM/HT unicast frames.
+        * We check if Short Preamble is needed for the CTS rate by
+        * checking the BSS's global flag.
+        * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
         */
-       if (sc->sc_protmode != PROT_M_NONE && !(bf->bf_flags & ATH9K_TXDESC_NOACK)
-           && (rt->info[rix].phy == WLAN_RC_PHY_OFDM ||
-               WLAN_RC_PHY_HT(rt->info[rix].phy))) {
-               if (sc->sc_protmode == PROT_M_RTSCTS)
-                       flags = ATH9K_TXDESC_RTSENA;
-               else if (sc->sc_protmode == PROT_M_CTSONLY)
-                       flags = ATH9K_TXDESC_CTSENA;
-
-               cix = rt->info[enable_g_protection].ctrl_rate;
-               rtsctsena = 1;
-       }
+       if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
+               ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode |
+                       rt->info[tx_info->control.rts_cts_rate_idx].short_preamble;
+       else
+               ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode;
 
-       /* For 11n, the default behavior is to enable RTS for hw retried frames.
-        * We enable the global flag here and let rate series flags determine
-        * which rates will actually use RTS.
+       /*
+        * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive.
+        * Check the first rate in the series to decide whether RTS/CTS
+        * or CTS-to-self has to be used.
         */
-       if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) {
-               /* 802.11g protection not needed, use our default behavior */
-               if (!rtsctsena)
-                       flags = ATH9K_TXDESC_RTSENA;
-       }
+       if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
+               flags = ATH9K_TXDESC_CTSENA;
+       else if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               flags = ATH9K_TXDESC_RTSENA;
 
-       /* Set protection if aggregate protection on */
+       /* FIXME: Handle aggregation protection */
        if (sc->sc_config.ath_aggr_prot &&
            (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
                flags = ATH9K_TXDESC_RTSENA;
-               cix = rt->info[enable_g_protection].ctrl_rate;
-               rtsctsena = 1;
        }
 
        /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
-       if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit))
+       if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->ah_caps.rts_aggr_limit))
                flags &= ~(ATH9K_TXDESC_RTSENA);
 
-       /*
-        * CTS transmit rate is derived from the transmit rate by looking in the
-        * h/w rate table.  We must also factor in whether or not a short
-        * preamble is to be used. NB: cix is set above where RTS/CTS is enabled
-        */
-       ctsrate = rt->info[cix].ratecode |
-               (bf_isshpreamble(bf) ? rt->info[cix].short_preamble : 0);
-
        for (i = 0; i < 4; i++) {
                if (!rates[i].count || (rates[i].idx < 0))
                        continue;
 
                rix = rates[i].idx;
-
-               series[i].Rate = rt->info[rix].ratecode |
-                       (bf_isshpreamble(bf) ? rt->info[rix].short_preamble : 0);
-
                series[i].Tries = rates[i].count;
+               series[i].ChSel = sc->sc_tx_chainmask;
 
-               series[i].RateFlags = (
-                       (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) ?
-                               ATH9K_RATESERIES_RTS_CTS : 0) |
-                       ((rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ?
-                               ATH9K_RATESERIES_2040 : 0) |
-                       ((rates[i].flags & IEEE80211_TX_RC_SHORT_GI) ?
-                               ATH9K_RATESERIES_HALFGI : 0);
+               if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+                       series[i].Rate = rt->info[rix].ratecode |
+                               rt->info[rix].short_preamble;
+               else
+                       series[i].Rate = rt->info[rix].ratecode;
+
+               if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+                       series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+               if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+                       series[i].RateFlags |= ATH9K_RATESERIES_2040;
+               if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
+                       series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
 
                series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
                         (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0,
                         (rates[i].flags & IEEE80211_TX_RC_SHORT_GI),
-                        bf_isshpreamble(bf));
-
-               series[i].ChSel = sc->sc_tx_chainmask;
-
-               if (rtsctsena)
-                       series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+                        (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE));
        }
 
        /* set dur_update_en for l-sig computation except for PS-Poll frames */
-       ath9k_hw_set11n_ratescenario(ah, ds, lastds, !bf_ispspoll(bf),
-                                    ctsrate, ctsduration,
-                                    series, 4, flags);
+       ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
+                                    bf->bf_lastbf->bf_desc,
+                                    !bf_ispspoll(bf), ctsrate,
+                                    0, series, 4, flags);
 
        if (sc->sc_config.ath_aggr_prot && flags)
-               ath9k_hw_set11n_burstduration(ah, ds, 8192);
+               ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
 }
 
 static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
@@ -1593,8 +1540,6 @@ static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
                bf->bf_state.bf_type |= BUF_BAR;
        if (ieee80211_is_pspoll(fc))
                bf->bf_state.bf_type |= BUF_PSPOLL;
-       if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
-               bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE;
        if ((conf_is_ht(&sc->hw->conf) && !is_pae(skb) &&
             (tx_info->flags & IEEE80211_TX_CTL_AMPDU)))
                bf->bf_state.bf_type |= BUF_HT;