From b34793ee27aa547fc9b4213f89036c9a0ecaad5d Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 2 Oct 2010 11:34:56 +0200 Subject: [PATCH] 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 Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) 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) void rt2800_txdone_entry(struct queue_entry *entry, u32 status) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); struct txdone_entry_desc txdesc; u32 word; u16 mcs, real_mcs; + int aggr, ampdu; __le32 *txwi; /* @@ -645,8 +647,33 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status) txdesc.flags = 0; txwi = rt2800_drv_get_txwi(entry); rt2x00_desc_read(txwi, 0, &word); + mcs = rt2x00_get_field32(word, TXWI_W0_MCS); + ampdu = rt2x00_get_field32(word, TXWI_W0_AMPDU); + real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS); + aggr = rt2x00_get_field32(status, TX_STA_FIFO_TX_AGGRE); + + /* + * If a frame was meant to be sent as a single non-aggregated MPDU + * but ended up in an aggregate the used tx rate doesn't correlate + * with the one specified in the TXWI as the whole aggregate is sent + * with the same rate. + * + * For example: two frames are sent to rt2x00, the first one sets + * AMPDU=1 and requests MCS7 whereas the second frame sets AMDPU=0 + * and requests MCS15. If the hw aggregates both frames into one + * AMDPU the tx status for both frames will contain MCS7 although + * the frame was sent successfully. + * + * Hence, replace the requested rate with the real tx rate to not + * confuse the rate control algortihm by providing clearly wrong + * data. + */ + if (aggr == 1 && ampdu == 0 && real_mcs != mcs) { + skbdesc->tx_rate_idx = real_mcs; + mcs = real_mcs; + } /* * Ralink has a retry mechanism using a global fallback