diff options
author | Felix Fietkau <nbd@openwrt.org> | 2008-10-05 12:05:48 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-10-06 18:14:57 -0400 |
commit | 2f7fe87034298d94301315ba4bb65c7284c709d0 (patch) | |
tree | e8583ae3686a243405b77d4ef6498bc4199ca3a2 /drivers/net | |
parent | 870abdf67170daa9f1022e55a35c469239fcc74c (diff) |
ath5k: implement multi-rate retry support, fix tx status reporting
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>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath5k/ath5k.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 48 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/desc.c | 69 |
3 files changed, 95 insertions, 26 deletions
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 7134c40d6a69..53ea439aff48 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h | |||
@@ -431,7 +431,9 @@ struct ath5k_tx_status { | |||
431 | u16 ts_seqnum; | 431 | u16 ts_seqnum; |
432 | u16 ts_tstamp; | 432 | u16 ts_tstamp; |
433 | u8 ts_status; | 433 | u8 ts_status; |
434 | u8 ts_rate; | 434 | u8 ts_rate[4]; |
435 | u8 ts_retry[4]; | ||
436 | u8 ts_final_idx; | ||
435 | s8 ts_rssi; | 437 | s8 ts_rssi; |
436 | u8 ts_shortretry; | 438 | u8 ts_shortretry; |
437 | u8 ts_longretry; | 439 | u8 ts_longretry; |
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 47be49acf55e..9b95c4049b31 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
@@ -541,6 +541,12 @@ ath5k_pci_probe(struct pci_dev *pdev, | |||
541 | goto err_irq; | 541 | goto err_irq; |
542 | } | 542 | } |
543 | 543 | ||
544 | /* set up multi-rate retry capabilities */ | ||
545 | if (sc->ah->ah_version == AR5K_AR5212) { | ||
546 | hw->max_altrates = 3; | ||
547 | hw->max_altrate_tries = 11; | ||
548 | } | ||
549 | |||
544 | /* Finish private driver data initialization */ | 550 | /* Finish private driver data initialization */ |
545 | ret = ath5k_attach(pdev, hw); | 551 | ret = ath5k_attach(pdev, hw); |
546 | if (ret) | 552 | if (ret) |
@@ -1173,7 +1179,9 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
1173 | struct sk_buff *skb = bf->skb; | 1179 | struct sk_buff *skb = bf->skb; |
1174 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1180 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1175 | unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; | 1181 | unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; |
1176 | int ret; | 1182 | struct ieee80211_rate *rate; |
1183 | unsigned int mrr_rate[3], mrr_tries[3]; | ||
1184 | int i, ret; | ||
1177 | 1185 | ||
1178 | flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; | 1186 | flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; |
1179 | 1187 | ||
@@ -1198,6 +1206,22 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
1198 | if (ret) | 1206 | if (ret) |
1199 | goto err_unmap; | 1207 | goto err_unmap; |
1200 | 1208 | ||
1209 | memset(mrr_rate, 0, sizeof(mrr_rate)); | ||
1210 | memset(mrr_tries, 0, sizeof(mrr_tries)); | ||
1211 | for (i = 0; i < 3; i++) { | ||
1212 | rate = ieee80211_get_alt_retry_rate(sc->hw, info, i); | ||
1213 | if (!rate) | ||
1214 | break; | ||
1215 | |||
1216 | mrr_rate[i] = rate->hw_value; | ||
1217 | mrr_tries[i] = info->control.retries[i].limit; | ||
1218 | } | ||
1219 | |||
1220 | ah->ah_setup_mrr_tx_desc(ah, ds, | ||
1221 | mrr_rate[0], mrr_tries[0], | ||
1222 | mrr_rate[1], mrr_tries[1], | ||
1223 | mrr_rate[2], mrr_tries[2]); | ||
1224 | |||
1201 | ds->ds_link = 0; | 1225 | ds->ds_link = 0; |
1202 | ds->ds_data = bf->skbaddr; | 1226 | ds->ds_data = bf->skbaddr; |
1203 | 1227 | ||
@@ -1814,7 +1838,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
1814 | struct ath5k_desc *ds; | 1838 | struct ath5k_desc *ds; |
1815 | struct sk_buff *skb; | 1839 | struct sk_buff *skb; |
1816 | struct ieee80211_tx_info *info; | 1840 | struct ieee80211_tx_info *info; |
1817 | int ret; | 1841 | int i, ret; |
1818 | 1842 | ||
1819 | spin_lock(&txq->lock); | 1843 | spin_lock(&txq->lock); |
1820 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { | 1844 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { |
@@ -1836,7 +1860,25 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
1836 | pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, | 1860 | pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, |
1837 | PCI_DMA_TODEVICE); | 1861 | PCI_DMA_TODEVICE); |
1838 | 1862 | ||
1839 | info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; | 1863 | memset(&info->status, 0, sizeof(info->status)); |
1864 | info->tx_rate_idx = ath5k_hw_to_driver_rix(sc, | ||
1865 | ts.ts_rate[ts.ts_final_idx]); | ||
1866 | info->status.retry_count = ts.ts_longretry; | ||
1867 | |||
1868 | for (i = 0; i < 4; i++) { | ||
1869 | struct ieee80211_tx_altrate *r = | ||
1870 | &info->status.retries[i]; | ||
1871 | |||
1872 | if (ts.ts_rate[i]) { | ||
1873 | r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); | ||
1874 | r->limit = ts.ts_retry[i]; | ||
1875 | } else { | ||
1876 | r->rate_idx = -1; | ||
1877 | r->limit = 0; | ||
1878 | } | ||
1879 | } | ||
1880 | |||
1881 | info->status.excessive_retries = 0; | ||
1840 | if (unlikely(ts.ts_status)) { | 1882 | if (unlikely(ts.ts_status)) { |
1841 | sc->ll_stats.dot11ACKFailureCount++; | 1883 | sc->ll_stats.dot11ACKFailureCount++; |
1842 | if (ts.ts_status & AR5K_TXERR_XRETRY) | 1884 | if (ts.ts_status & AR5K_TXERR_XRETRY) |
diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c index d45b90a6e06c..dd1374052ba9 100644 --- a/drivers/net/wireless/ath5k/desc.c +++ b/drivers/net/wireless/ath5k/desc.c | |||
@@ -318,6 +318,15 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, | |||
318 | return 0; | 318 | return 0; |
319 | } | 319 | } |
320 | 320 | ||
321 | /* no mrr support for cards older than 5212 */ | ||
322 | static int | ||
323 | ath5k_hw_setup_no_mrr(struct ath5k_hw *ah, struct ath5k_desc *desc, | ||
324 | unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, | ||
325 | u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) | ||
326 | { | ||
327 | return 0; | ||
328 | } | ||
329 | |||
321 | /* | 330 | /* |
322 | * Proccess the tx status descriptor on 5210/5211 | 331 | * Proccess the tx status descriptor on 5210/5211 |
323 | */ | 332 | */ |
@@ -352,8 +361,10 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, | |||
352 | AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); | 361 | AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); |
353 | ts->ts_antenna = 1; | 362 | ts->ts_antenna = 1; |
354 | ts->ts_status = 0; | 363 | ts->ts_status = 0; |
355 | ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0, | 364 | ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0, |
356 | AR5K_2W_TX_DESC_CTL0_XMIT_RATE); | 365 | AR5K_2W_TX_DESC_CTL0_XMIT_RATE); |
366 | ts->ts_retry[0] = ts->ts_longretry; | ||
367 | ts->ts_final_idx = 0; | ||
357 | 368 | ||
358 | if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { | 369 | if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { |
359 | if (tx_status->tx_status_0 & | 370 | if (tx_status->tx_status_0 & |
@@ -405,29 +416,43 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, | |||
405 | AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; | 416 | AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; |
406 | ts->ts_status = 0; | 417 | ts->ts_status = 0; |
407 | 418 | ||
408 | switch (AR5K_REG_MS(tx_status->tx_status_1, | 419 | ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, |
409 | AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) { | 420 | AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX); |
410 | case 0: | 421 | |
411 | ts->ts_rate = tx_ctl->tx_control_3 & | 422 | /* The longretry counter has the number of un-acked retries |
412 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; | 423 | * for the final rate. To get the total number of retries |
413 | break; | 424 | * we have to add the retry counters for the other rates |
425 | * as well | ||
426 | */ | ||
427 | ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; | ||
428 | switch (ts->ts_final_idx) { | ||
429 | case 3: | ||
430 | ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3, | ||
431 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); | ||
432 | |||
433 | ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, | ||
434 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); | ||
435 | ts->ts_longretry += ts->ts_retry[2]; | ||
436 | /* fall through */ | ||
437 | case 2: | ||
438 | ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3, | ||
439 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); | ||
440 | |||
441 | ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, | ||
442 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); | ||
443 | ts->ts_longretry += ts->ts_retry[1]; | ||
444 | /* fall through */ | ||
414 | case 1: | 445 | case 1: |
415 | ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, | 446 | ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3, |
416 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); | 447 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); |
417 | ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, | 448 | |
449 | ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, | ||
418 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); | 450 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); |
419 | break; | 451 | ts->ts_longretry += ts->ts_retry[0]; |
420 | case 2: | 452 | /* fall through */ |
421 | ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, | 453 | case 0: |
422 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); | 454 | ts->ts_rate[0] = tx_ctl->tx_control_3 & |
423 | ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, | 455 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; |
424 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); | ||
425 | break; | ||
426 | case 3: | ||
427 | ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, | ||
428 | AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); | ||
429 | ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, | ||
430 | AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3); | ||
431 | break; | 456 | break; |
432 | } | 457 | } |
433 | 458 | ||
@@ -653,7 +678,7 @@ int ath5k_hw_init_desc_functions(struct ath5k_hw *ah) | |||
653 | } else { | 678 | } else { |
654 | ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc; | 679 | ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc; |
655 | ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; | 680 | ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; |
656 | ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc; | 681 | ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_no_mrr; |
657 | ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; | 682 | ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; |
658 | } | 683 | } |
659 | 684 | ||