aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHelmut Schaa <helmut.schaa@googlemail.com>2010-10-02 05:34:56 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-05 13:35:29 -0400
commitb34793ee27aa547fc9b4213f89036c9a0ecaad5d (patch)
tree10e244f45980d48cba3e30928956086ebc2ebb2c
parent01e946f22ae4bafe370d263f2ef499b8b232aec1 (diff)
rt2x00: Work around hw aggregation oddity in rt2800
If a frame is not meant to be sent as AMPDU or part of it the hw might still decide to aggregate this frame if a previous frame started an AMPDU. However, this will limit the usefulness of the reported tx rate since the reported rate will be the one specified in the TXWI of the first frame and thus it is not possible to reliably caculate the number of retrys by substracting the reported tx rate from the tx rate in the TXWI. To fix this issue, only report the successful rate for frames that were not meant to be aggregated but ended up in an aggregate. Example: Frame A (MCS7, AMPDU=1) B (MCS7, AMPDU=1) C (MCS12, AMDPU=0, PROBE_RATE) Although frame C shoudn't be aggregated the hw might sill put it into an AMPDU together with A and B. If the transmission succeeds the tx status will contain MCS7 for all three frames. In that case we should only report MCS7 as success rate and avoid reporting MCS12-MCS8 as failed tx attempts as this will affect the future rate control decisions. This oddity might strike us in other scenarious as well but the most common "wrong" report happened for frames used to probe a different tx rate. This improves the rate control decisions notable. Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com> Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 028715730b2c..7f040b0eac36 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -634,9 +634,11 @@ static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg)
634void rt2800_txdone_entry(struct queue_entry *entry, u32 status) 634void rt2800_txdone_entry(struct queue_entry *entry, u32 status)
635{ 635{
636 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; 636 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
637 struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
637 struct txdone_entry_desc txdesc; 638 struct txdone_entry_desc txdesc;
638 u32 word; 639 u32 word;
639 u16 mcs, real_mcs; 640 u16 mcs, real_mcs;
641 int aggr, ampdu;
640 __le32 *txwi; 642 __le32 *txwi;
641 643
642 /* 644 /*
@@ -645,8 +647,33 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status)
645 txdesc.flags = 0; 647 txdesc.flags = 0;
646 txwi = rt2800_drv_get_txwi(entry); 648 txwi = rt2800_drv_get_txwi(entry);
647 rt2x00_desc_read(txwi, 0, &word); 649 rt2x00_desc_read(txwi, 0, &word);
650
648 mcs = rt2x00_get_field32(word, TXWI_W0_MCS); 651 mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
652 ampdu = rt2x00_get_field32(word, TXWI_W0_AMPDU);
653
649 real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS); 654 real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS);
655 aggr = rt2x00_get_field32(status, TX_STA_FIFO_TX_AGGRE);
656
657 /*
658 * If a frame was meant to be sent as a single non-aggregated MPDU
659 * but ended up in an aggregate the used tx rate doesn't correlate
660 * with the one specified in the TXWI as the whole aggregate is sent
661 * with the same rate.
662 *
663 * For example: two frames are sent to rt2x00, the first one sets
664 * AMPDU=1 and requests MCS7 whereas the second frame sets AMDPU=0
665 * and requests MCS15. If the hw aggregates both frames into one
666 * AMDPU the tx status for both frames will contain MCS7 although
667 * the frame was sent successfully.
668 *
669 * Hence, replace the requested rate with the real tx rate to not
670 * confuse the rate control algortihm by providing clearly wrong
671 * data.
672 */
673 if (aggr == 1 && ampdu == 0 && real_mcs != mcs) {
674 skbdesc->tx_rate_idx = real_mcs;
675 mcs = real_mcs;
676 }
650 677
651 /* 678 /*
652 * Ralink has a retry mechanism using a global fallback 679 * Ralink has a retry mechanism using a global fallback