From 293dff78ee058ec1e0b90e05a803c512b6a2097f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 15 Feb 2017 10:25:10 +0100 Subject: [PATCH] rt2x00: use txdone_nomatch on rt2800usb If we do not match skb entry, provide tx status via nomatch procedure. Currently in that case we do rt2x00lib_txdone_noinfo(TXDONE_NOINFO), which actually assume that entry->skb was posted without retries and provide rate saved in skb desc as successful. Patch changed that to rate read from TX_STAT_FIFO, however still do not provide correct number of retries. On SoC/PCI devices we keep providing status via standard txdone procedure, no change in those devices, though we should thing about it. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/ralink/rt2x00/rt2800lib.c | 31 +++++++++++++++---- .../net/wireless/ralink/rt2x00/rt2800lib.h | 3 +- .../net/wireless/ralink/rt2x00/rt2800mmio.c | 2 +- .../net/wireless/ralink/rt2x00/rt2800usb.c | 18 +++++------ 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 46405cce35e0..4a7bec708a13 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -852,7 +852,8 @@ void rt2800_process_rxwi(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2800_process_rxwi); -void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi) +void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, + bool match) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; @@ -860,8 +861,7 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi) struct txdone_entry_desc txdesc; u32 word; u16 mcs, real_mcs; - int aggr, ampdu; - int wcid; + int aggr, ampdu, wcid, ack_req; /* * Obtain the status about this packet. @@ -875,6 +875,7 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi) real_mcs = rt2x00_get_field32(status, TX_STA_FIFO_MCS); aggr = rt2x00_get_field32(status, TX_STA_FIFO_TX_AGGRE); wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID); + ack_req = rt2x00_get_field32(status, TX_STA_FIFO_TX_ACK_REQUIRED); /* * If a frame was meant to be sent as a single non-aggregated MPDU @@ -891,8 +892,12 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi) * Hence, replace the requested rate with the real tx rate to not * confuse the rate control algortihm by providing clearly wrong * data. - */ - if (unlikely(aggr == 1 && ampdu == 0 && real_mcs != mcs)) { + * + * FIXME: if we do not find matching entry, we tell that frame was + * posted without any retries. We need to find a way to fix that + * and provide retry count. + */ + if (unlikely((aggr == 1 && ampdu == 0 && real_mcs != mcs)) || !match) { skbdesc->tx_rate_idx = real_mcs; mcs = real_mcs; } @@ -900,6 +905,9 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi) if (aggr == 1 || ampdu == 1) __set_bit(TXDONE_AMPDU, &txdesc.flags); + if (!ack_req) + __set_bit(TXDONE_NO_ACK_REQ, &txdesc.flags); + /* * Ralink has a retry mechanism using a global fallback * table. We setup this fallback table to try the immediate @@ -931,7 +939,18 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi) if (txdesc.retry) __set_bit(TXDONE_FALLBACK, &txdesc.flags); - rt2x00lib_txdone(entry, &txdesc); + if (!match) { + /* RCU assures non-null sta will not be freed by mac80211. */ + rcu_read_lock(); + if (likely(wcid >= WCID_START && wcid <= WCID_END)) + skbdesc->sta = drv_data->wcid_to_sta[wcid - WCID_START]; + else + skbdesc->sta = NULL; + rt2x00lib_txdone_nomatch(entry, &txdesc); + rcu_read_unlock(); + } else { + rt2x00lib_txdone(entry, &txdesc); + } } EXPORT_SYMBOL_GPL(rt2800_txdone_entry); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h index 6811d677a6e7..d9ef260d542a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h @@ -191,7 +191,8 @@ void rt2800_write_tx_data(struct queue_entry *entry, struct txentry_desc *txdesc); void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc); -void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32* txwi); +void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, + bool match); void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); void rt2800_clear_beacon(struct queue_entry *entry); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c index de4790b41be7..3ab3b5323897 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c @@ -239,7 +239,7 @@ static bool rt2800mmio_txdone_release_entries(struct queue_entry *entry, { if (test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) { rt2800_txdone_entry(entry, entry->status, - rt2800mmio_get_txwi(entry)); + rt2800mmio_get_txwi(entry), true); return false; } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index 205a7b8ac8a7..f11e3f532a84 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -501,8 +501,7 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry) /* * TX control handlers */ -static enum txdone_entry_desc_flags -rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) +static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) { __le32 *txwi; u32 word; @@ -515,7 +514,7 @@ rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) * frame. */ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) - return TXDONE_FAILURE; + return false; wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); @@ -537,10 +536,10 @@ rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) rt2x00_dbg(entry->queue->rt2x00dev, "TX status report missed for queue %d entry %d\n", entry->queue->qid, entry->entry_idx); - return TXDONE_UNKNOWN; + return false; } - return TXDONE_SUCCESS; + return true; } static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) @@ -549,7 +548,7 @@ static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) struct queue_entry *entry; u32 reg; u8 qid; - enum txdone_entry_desc_flags done_status; + bool match; while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { /* @@ -574,11 +573,8 @@ static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) break; } - done_status = rt2800usb_txdone_entry_check(entry, reg); - if (likely(done_status == TXDONE_SUCCESS)) - rt2800_txdone_entry(entry, reg, rt2800usb_get_txwi(entry)); - else - rt2x00lib_txdone_noinfo(entry, done_status); + match = rt2800usb_txdone_entry_check(entry, reg); + rt2800_txdone_entry(entry, reg, rt2800usb_get_txwi(entry), match); } } -- 2.30.2