add the new compat-wireless for 2.6.27 + multi-rate retry and minstrel patches, renam...
[openwrt/svn-archive/archive.git] / package / mac80211 / patches / 250-ath5k_mrr.patch
diff --git a/package/mac80211/patches/250-ath5k_mrr.patch b/package/mac80211/patches/250-ath5k_mrr.patch
new file mode 100644 (file)
index 0000000..ff15fd4
--- /dev/null
@@ -0,0 +1,208 @@
+Clean up the tx status reporting, fix retry counters (short retries are
+virtual collisions, not actual retries). Implement multi-rate retry
+support.
+This also fixes strong throughput fluctuations with rc80211_pid
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/drivers/net/wireless/ath5k/base.c
++++ b/drivers/net/wireless/ath5k/base.c
+@@ -530,6 +530,12 @@
+               goto err_irq;
+       }
++      /* set up multi-rate retry capabilities */
++      if (sc->ah->ah_version == AR5K_AR5212) {
++              hw->max_altrates = 3;
++              hw->max_altrate_tries = 11;
++      }
++
+       /* Finish private driver data initialization */
+       ret = ath5k_attach(pdev, hw);
+       if (ret)
+@@ -1149,7 +1155,9 @@
+       struct sk_buff *skb = bf->skb;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID;
+-      int ret;
++      struct ieee80211_rate *rate;
++      unsigned int mrr_rate[3], mrr_tries[3];
++      int i, ret;
+       flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
+@@ -1174,6 +1182,22 @@
+       if (ret)
+               goto err_unmap;
++      memset(mrr_rate, 0, sizeof(mrr_rate));
++      memset(mrr_tries, 0, sizeof(mrr_tries));
++      for (i = 0; i < 3; i++) {
++              rate = ieee80211_get_alt_retry_rate(sc->hw, info, i);
++              if (!rate)
++                      break;
++
++              mrr_rate[i] = rate->hw_value;
++              mrr_tries[i] = info->control.retries[i].limit;
++      }
++
++      ah->ah_setup_mrr_tx_desc(ah, ds,
++              mrr_rate[0], mrr_tries[0],
++              mrr_rate[1], mrr_tries[1],
++              mrr_rate[2], mrr_tries[2]);
++
+       ds->ds_link = 0;
+       ds->ds_data = bf->skbaddr;
+@@ -1790,7 +1814,7 @@
+       struct ath5k_desc *ds;
+       struct sk_buff *skb;
+       struct ieee80211_tx_info *info;
+-      int ret;
++      int i, ret;
+       spin_lock(&txq->lock);
+       list_for_each_entry_safe(bf, bf0, &txq->q, list) {
+@@ -1812,7 +1836,25 @@
+               pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
+                               PCI_DMA_TODEVICE);
+-              info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
++              memset(&info->status, 0, sizeof(info->status));
++              info->tx_rate_idx = ath5k_hw_to_driver_rix(sc,
++                              ts.ts_rate[ts.ts_final_idx]);
++              info->status.retry_count = ts.ts_longretry;
++
++              for (i = 0; i < 4; i++) {
++                      struct ieee80211_tx_altrate *r =
++                              &info->status.retries[i];
++
++                      if (ts.ts_rate[i]) {
++                              r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
++                              r->limit = ts.ts_retry[i];
++                      } else {
++                              r->rate_idx = -1;
++                              r->limit = 0;
++                      }
++              }
++
++              info->status.excessive_retries = 0;
+               if (unlikely(ts.ts_status)) {
+                       sc->ll_stats.dot11ACKFailureCount++;
+                       if (ts.ts_status & AR5K_TXERR_XRETRY)
+--- a/drivers/net/wireless/ath5k/desc.c
++++ b/drivers/net/wireless/ath5k/desc.c
+@@ -318,6 +318,15 @@
+       return 0;
+ }
++/* no mrr support for cards older than 5212 */
++static int
++ath5k_hw_setup_no_mrr(struct ath5k_hw *ah, struct ath5k_desc *desc,
++      unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
++      u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3)
++{
++      return 0;
++}
++
+ /*
+  * Proccess the tx status descriptor on 5210/5211
+  */
+@@ -352,8 +361,10 @@
+               AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+       ts->ts_antenna = 1;
+       ts->ts_status = 0;
+-      ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0,
++      ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0,
+               AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
++      ts->ts_retry[0] = ts->ts_longretry;
++      ts->ts_final_idx = 0;
+       if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+               if (tx_status->tx_status_0 &
+@@ -405,29 +416,43 @@
+               AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
+       ts->ts_status = 0;
+-      switch (AR5K_REG_MS(tx_status->tx_status_1,
+-                      AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) {
+-      case 0:
+-              ts->ts_rate = tx_ctl->tx_control_3 &
+-                      AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+-              break;
++      ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1,
++                      AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX);
++
++      /* The longretry counter has the number of un-acked retries
++       * for the final rate. To get the total number of retries
++       * we have to add the retry counters for the other rates
++       * as well
++       */
++      ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry;
++      switch (ts->ts_final_idx) {
++      case 3:
++              ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3,
++                      AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
++
++              ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2,
++                      AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
++              ts->ts_longretry += ts->ts_retry[2];
++              /* fall through */
++      case 2:
++              ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3,
++                      AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
++
++              ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2,
++                      AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
++              ts->ts_longretry += ts->ts_retry[1];
++              /* fall through */
+       case 1:
+-              ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
++              ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3,
+                       AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
+-              ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
++
++              ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2,
+                       AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
+-              break;
+-      case 2:
+-              ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
+-                      AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
+-              ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
+-                      AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
+-              break;
+-      case 3:
+-              ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
+-                      AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
+-              ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
+-                      AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3);
++              ts->ts_longretry += ts->ts_retry[0];
++              /* fall through */
++      case 0:
++              ts->ts_rate[0] = tx_ctl->tx_control_3 &
++                      AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+               break;
+       }
+@@ -653,7 +678,7 @@
+       } else {
+               ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
+               ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
+-              ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc;
++              ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_no_mrr;
+               ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
+       }
+--- a/drivers/net/wireless/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath5k/ath5k.h
+@@ -418,7 +418,9 @@
+       u16     ts_seqnum;
+       u16     ts_tstamp;
+       u8      ts_status;
+-      u8      ts_rate;
++      u8      ts_rate[4];
++      u8      ts_retry[4];
++      u8      ts_final_idx;
+       s8      ts_rssi;
+       u8      ts_shortretry;
+       u8      ts_longretry;