]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/ath9k/rc.c
ath9k: Fix PTK/GTK handshake timeout
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / ath9k / rc.c
index 04ab457a8faa3f3bce73692b583a61866c72e6e2..0e3e2b7dd2ecb6ee3ba0ca79d651e4b1fbd35a23 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
+#include "ath9k.h"
 
 static struct ath_rate_table ar5416_11na_ratetable = {
        42,
-       {0},
        {
                { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
                        5400, 0x0b, 0x00, 12,
                        0, 2, 1, 0, 0, 0, 0, 0 },
-               { VALID,        VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
+               { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
                        7800,  0x0f, 0x00, 18,
                        0, 3, 1, 1, 1, 1, 1, 0 },
                { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
@@ -158,7 +157,6 @@ static struct ath_rate_table ar5416_11na_ratetable = {
 
 static struct ath_rate_table ar5416_11ng_ratetable = {
        46,
-       {0},
        {
                { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
                        900, 0x1b, 0x00, 2,
@@ -306,7 +304,6 @@ static struct ath_rate_table ar5416_11ng_ratetable = {
 
 static struct ath_rate_table ar5416_11a_ratetable = {
        8,
-       {0},
        {
                { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
                        5400, 0x0b, 0x00, (0x80|12),
@@ -340,7 +337,6 @@ static struct ath_rate_table ar5416_11a_ratetable = {
 
 static struct ath_rate_table ar5416_11g_ratetable = {
        12,
-       {0},
        {
                { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
                        900, 0x1b, 0x00, 2,
@@ -386,7 +382,6 @@ static struct ath_rate_table ar5416_11g_ratetable = {
 
 static struct ath_rate_table ar5416_11b_ratetable = {
        4,
-       {0},
        {
                { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
                        900, 0x1b,  0x00, (0x80|2),
@@ -490,7 +485,7 @@ static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table,
 
 static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
 {
-       if (WLAN_RC_PHY_HT(phy) & !(capflag & WLAN_RC_HT_FLAG))
+       if (WLAN_RC_PHY_HT(phy) && !(capflag & WLAN_RC_HT_FLAG))
                return 0;
        if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG))
                return 0;
@@ -636,8 +631,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
 static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
                             struct ath_rate_priv *ath_rc_priv,
                             struct ath_rate_table *rate_table,
-                            int probe_allowed, int *is_probing,
-                            int is_retry)
+                            int *is_probing)
 {
        u32 dt, best_thruput, this_thruput, now_msec;
        u8 rate, next_rate, best_rate, maxindex, minindex;
@@ -719,13 +713,6 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
        }
 
        rate = best_rate;
-
-       /* if we are retrying for more than half the number
-        * of max retries, use the min rate for the next retry
-        */
-       if (is_retry)
-               rate = ath_rc_priv->valid_rate_index[minindex];
-
        ath_rc_priv->rssi_last_lookup = rssi_last;
 
        /*
@@ -733,13 +720,12 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
         * non-monoticity of 11g's rate table
         */
 
-       if (rate >= ath_rc_priv->rate_max_phy && probe_allowed) {
+       if (rate >= ath_rc_priv->rate_max_phy) {
                rate = ath_rc_priv->rate_max_phy;
 
                /* Probe the next allowed phy state */
-               /* FIXME:XXXX Check to make sure ratMax is checked properly */
                if (ath_rc_get_nextvalid_txrate(rate_table,
-                                               ath_rc_priv, rate, &next_rate) &&
+                                       ath_rc_priv, rate, &next_rate) &&
                    (now_msec - ath_rc_priv->probe_time >
                     rate_table->probe_interval) &&
                    (ath_rc_priv->hw_maxretry_pktcnt >= 1)) {
@@ -761,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;
@@ -778,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,
@@ -809,54 +835,56 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc,
 
 static void ath_rc_ratefind(struct ath_softc *sc,
                            struct ath_rate_priv *ath_rc_priv,
-                           int num_tries, int num_rates,
-                           struct ieee80211_tx_info *tx_info, int *is_probe,
-                           int is_retry)
+                           struct ieee80211_tx_rate_control *txrc)
 {
-       u8 try_per_rate = 0, i = 0, rix, nrix;
        struct ath_rate_table *rate_table;
+       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;
 
        rate_table = sc->cur_rate_table;
-       rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, 1,
-                                is_probe, is_retry);
+       rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe);
        nrix = rix;
 
-       if (*is_probe) {
+       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++], 1, nrix, 0);
+               ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
+                                      1, nrix, 0);
 
-               try_per_rate = (num_tries/num_rates);
+               try_per_rate = (ATH_11N_TXMAXTRY/4);
                /* Get the next tried/allowed rate. No RTS for the next series
                 * after the probe rate
                 */
-               nrix = ath_rc_rate_getidx(sc,
-                       ath_rc_priv, rate_table, nrix, 1, 0);
-               ath_rc_rate_set_series(rate_table,
-                       &rates[i++], try_per_rate, nrix, 0);
+               nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
+                                         rate_table, nrix, 1, 0);
+               ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
+                                      try_per_rate, nrix, 0);
        } else {
-               try_per_rate = (num_tries/num_rates);
+               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++], try_per_rate, nrix, 0);
+               ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
+                                      try_per_rate, nrix, 0);
        }
 
        /* Fill in the other rates for multirate retry */
-       for ( ; i < num_rates; i++) {
+       for ( ; i < 4; i++) {
                u8 try_num;
                u8 min_rate;
 
-               try_num = ((i + 1) == num_rates) ?
-                       num_tries - (try_per_rate * i) : try_per_rate ;
-               min_rate = (((i + 1) == num_rates) && 0);
+               try_num = ((i + 1) == 4) ?
+                       ATH_11N_TXMAXTRY - (try_per_rate * i) : try_per_rate ;
+               min_rate = (((i + 1) == 4) && 0);
 
                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], try_num, nrix, 1);
+               ath_rc_rate_set_series(rate_table, &rates[i], txrc,
+                                      try_num, nrix, 1);
        }
 
        /*
@@ -875,7 +903,7 @@ static void ath_rc_ratefind(struct ath_softc *sc,
         * above conditions.
         */
        if ((sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ) &&
-           (sc->hw->conf.ht.enabled)) {
+           (conf_is_ht(&sc->hw->conf))) {
                u8 dot11rate = rate_table->info[rix].dot11rate;
                u8 phy = rate_table->info[rix].phy;
                if (i == 4 &&
@@ -885,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,
@@ -1221,6 +1267,8 @@ static void ath_rc_update_ht(struct ath_softc *sc,
                ath_rc_priv->per_down_time = now_msec;
        }
 
+       ath_debug_stat_retries(sc, tx_rate, xretries, retries);
+
 #undef CHK_RSSI
 }
 
@@ -1344,15 +1392,16 @@ static void ath_rc_init(struct ath_softc *sc,
        struct ath_rateset *rateset = &ath_rc_priv->neg_rates;
        u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
        u8 i, j, k, hi = 0, hthi = 0;
+       struct ath_hw *ah = sc->sc_ah;
 
        /* FIXME: Adhoc */
-       if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) ||
-           (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)) {
+       if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) ||
+           (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) {
                bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
                rate_table = ath_choose_rate_table(sc, sband->band,
                                                   sta->ht_cap.ht_supported,
                                                   is_cw_40);
-       } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
+       } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
                /* cur_rate_table would be set on init through config() */
                rate_table = sc->cur_rate_table;
        }
@@ -1363,9 +1412,14 @@ static void ath_rc_init(struct ath_softc *sc,
        }
 
        if (sta->ht_cap.ht_supported) {
-               ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG);
+               ath_rc_priv->ht_cap = WLAN_RC_HT_FLAG;
+               if (sc->sc_ah->caps.tx_chainmask != 1 &&
+                       ath9k_hw_getcapability(ah, ATH9K_CAP_DS, 0, NULL))
+                       ath_rc_priv->ht_cap |= WLAN_RC_DS_FLAG;
                if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
                        ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG;
+               if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
+                       ath_rc_priv->ht_cap |= WLAN_RC_SGI_FLAG;
        }
 
        /* Initial rate table size. Will change depending
@@ -1395,16 +1449,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);
        }
@@ -1467,7 +1521,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
         */
        if (tx_info_priv->tx.ts_flags &
            (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
-           ((sc->sc_ah->ah_txTrigLevel) >= ath_rc_priv->tx_triglevel_max)) {
+           ((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) {
                tx_status = 1;
                is_underrun = 1;
        }
@@ -1480,6 +1534,23 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
                         (is_underrun) ? ATH_11N_TXMAXTRY :
                         tx_info_priv->tx.ts_longretry);
 
+       /* Check if aggregation has to be enabled for this tid */
+       if (conf_is_ht(&sc->hw->conf) &&
+           !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+               if (ieee80211_is_data_qos(fc)) {
+                       u8 *qc, tid;
+                       struct ath_node *an;
+
+                       qc = ieee80211_get_qos_ctl(hdr);
+                       tid = qc[0] & 0xf;
+                       an = (struct ath_node *)sta->drv_priv;
+
+                       if(ath_tx_aggr_check(sc, an, tid))
+                               ieee80211_start_tx_ba_session(sc->hw, hdr->addr1, tid);
+               }
+       }
+
+       ath_debug_stat_rc(sc, skb);
 exit:
        kfree(tx_info_priv);
 }
@@ -1490,11 +1561,9 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        struct ieee80211_supported_band *sband = txrc->sband;
        struct sk_buff *skb = txrc->skb;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ath_softc *sc = priv;
-       struct ieee80211_hw *hw = sc->hw;
        struct ath_rate_priv *ath_rc_priv = priv_sta;
-       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-       int is_probe = 0;
        __le16 fc = hdr->frame_control;
 
        /* lowest rate for management and multicast/broadcast frames */
@@ -1507,23 +1576,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        }
 
        /* Find tx rate for unicast frames */
-       ath_rc_ratefind(sc, ath_rc_priv, ATH_11N_TXMAXTRY, 4,
-                       tx_info, &is_probe, false);
-
-       /* Check if aggregation has to be enabled for this tid */
-       if (hw->conf.ht.enabled) {
-               if (ieee80211_is_data_qos(fc)) {
-                       u8 *qc, tid;
-                       struct ath_node *an;
-
-                       qc = ieee80211_get_qos_ctl(hdr);
-                       tid = qc[0] & 0xf;
-                       an = (struct ath_node *)sta->drv_priv;
-
-                       if(ath_tx_aggr_check(sc, an, tid))
-                               ieee80211_start_tx_ba_session(hw, hdr->addr1, tid);
-               }
-       }
+       ath_rc_ratefind(sc, ath_rc_priv, txrc);
 }
 
 static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
@@ -1578,7 +1631,7 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
        }
 
        rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
-       rate_priv->tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max;
+       rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max;
 
        return rate_priv;
 }
@@ -1607,16 +1660,8 @@ static void ath_setup_rate_table(struct ath_softc *sc,
 {
        int i;
 
-       for (i = 0; i < 256; i++)
-               rate_table->rateCodeToIndex[i] = (u8)-1;
-
        for (i = 0; i < rate_table->rate_cnt; i++) {
-               u8 code = rate_table->info[i].ratecode;
                u8 cix = rate_table->info[i].ctrl_rate;
-               u8 sh = rate_table->info[i].short_preamble;
-
-               rate_table->rateCodeToIndex[code] = i;
-               rate_table->rateCodeToIndex[code | sh] = i;
 
                rate_table->info[i].lpAckDuration =
                        ath9k_hw_computetxtime(sc->sc_ah, rate_table,