summaryrefslogtreecommitdiff
path: root/package/mac80211/patches/250-ath5k_mrr.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/patches/250-ath5k_mrr.patch')
-rw-r--r--package/mac80211/patches/250-ath5k_mrr.patch208
1 files changed, 208 insertions, 0 deletions
diff --git a/package/mac80211/patches/250-ath5k_mrr.patch b/package/mac80211/patches/250-ath5k_mrr.patch
new file mode 100644
index 0000000..ff15fd4
--- /dev/null
+++ b/package/mac80211/patches/250-ath5k_mrr.patch
@@ -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;