From d4c999bb891725b71ae38416cc6d5cfa99938ae4 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 13 Feb 2019 19:47:18 +0100 Subject: mac80211: rt2x00: backport accepted and pending patches from upstream backport from wireless-drivers-next, replacing some existing patches in our tree (marked with '=' are those which were already present): f483039cf51a rt2x00: use simple_read_from_buffer() =5c656c71b1bf rt2800: move usb specific txdone/txstatus routines to rt2800lib =0b0d556e0ebb rt2800mmio: use txdone/txstatus routines from lib =5022efb50f62 rt2x00: do not check for txstatus timeout every time on tasklet =adf26a356f13 rt2x00: use different txstatus timeouts when flushing =0240564430c0 rt2800: flush and txstatus rework for rt2800mmio 6eba8fd22352 rt2x00: rt2400pci: mark expected switch fall-through 10bb92217747 rt2x00: rt2500pci: mark expected switch fall-through 916e6bbcfcff rt2x00: rt2800lib: mark expected switch fall-throughs 641dd8068ecb rt2x00: rt61pci: mark expected switch fall-through 750afb08ca71 cross-tree: phase out dma_zalloc_coherent() =c2e28ef7711f rt2x00: reduce tx power to nominal level on RT6352 a4296994eb80 rt2x00: Work around a firmware bug with shared keys 2587791d5758 rt2x00: no need to check return value of debugfs_create functions pending on linux-wireless: rt2x00: remove unneeded check rt2x00: remove confusing AGC register rt2800: enable TX_PIN_CFG_LNA_PE_ bits per band rt2800: enable TX_PIN_CFG_RFRX_EN only for MT7620 rt2800: comment and simplify AGC init for RT6352 rt2x00: do not print error when queue is full rt2800: partially restore old mmio txstatus behaviour rt2800: new flush implementation for SoC devices rt2800: move txstatus pending routine rt2800mmio: fetch tx status changes rt2800mmio: use timer and work for handling tx statuses timeouts rt2x00: remove last_nostatus_check rt2x00: remove not used entry field rt2x00mmio: remove legacy comment While at it also rename some existing patches now that there are separate folders with patches for each driver to make things a bit nicer to handle. Signed-off-by: Daniel Golle --- ...-usb-specific-txdone-txstatus-routines-to.patch | 357 +++++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 package/kernel/mac80211/patches/rt2x00/002-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch (limited to 'package/kernel/mac80211/patches/rt2x00/002-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch') diff --git a/package/kernel/mac80211/patches/rt2x00/002-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch b/package/kernel/mac80211/patches/rt2x00/002-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch new file mode 100644 index 0000000000..a883258a4c --- /dev/null +++ b/package/kernel/mac80211/patches/rt2x00/002-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch @@ -0,0 +1,357 @@ +From 5c656c71b1bf5611ce8262bab338104e04d10b8d Mon Sep 17 00:00:00 2001 +From: Stanislaw Gruszka +Date: Wed, 26 Sep 2018 12:24:53 +0200 +Subject: [PATCH 02/28] rt2800: move usb specific txdone/txstatus routines to + rt2800lib + +In order to reuse usb txdone/txstatus routines for mmio, move them +to common rt2800lib.c file. + +Signed-off-by: Stanislaw Gruszka +Signed-off-by: Kalle Valo +--- + .../net/wireless/ralink/rt2x00/rt2800lib.c | 138 +++++++++++++++++ + .../net/wireless/ralink/rt2x00/rt2800lib.h | 3 + + .../net/wireless/ralink/rt2x00/rt2800usb.c | 143 +----------------- + 3 files changed, 145 insertions(+), 139 deletions(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -957,6 +957,47 @@ static void rt2800_rate_from_status(stru + skbdesc->tx_rate_flags = flags; + } + ++static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg) ++{ ++ __le32 *txwi; ++ u32 word; ++ int wcid, ack, pid; ++ int tx_wcid, tx_ack, tx_pid, is_agg; ++ ++ /* ++ * This frames has returned with an IO error, ++ * so the status report is not intended for this ++ * frame. ++ */ ++ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) ++ return false; ++ ++ wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); ++ ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); ++ pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); ++ is_agg = rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE); ++ ++ /* ++ * Validate if this TX status report is intended for ++ * this entry by comparing the WCID/ACK/PID fields. ++ */ ++ txwi = rt2800_drv_get_txwi(entry); ++ ++ word = rt2x00_desc_read(txwi, 1); ++ tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); ++ tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); ++ tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); ++ ++ if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) { ++ rt2x00_dbg(entry->queue->rt2x00dev, ++ "TX status report missed for queue %d entry %d\n", ++ entry->queue->qid, entry->entry_idx); ++ return false; ++ } ++ ++ return true; ++} ++ + void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, + bool match) + { +@@ -1059,6 +1100,103 @@ void rt2800_txdone_entry(struct queue_en + } + EXPORT_SYMBOL_GPL(rt2800_txdone_entry); + ++void rt2800_txdone(struct rt2x00_dev *rt2x00dev) ++{ ++ struct data_queue *queue; ++ struct queue_entry *entry; ++ u32 reg; ++ u8 qid; ++ bool match; ++ ++ while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { ++ /* ++ * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is ++ * guaranteed to be one of the TX QIDs . ++ */ ++ qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); ++ queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); ++ ++ if (unlikely(rt2x00queue_empty(queue))) { ++ rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n", ++ qid); ++ break; ++ } ++ ++ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); ++ ++ if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || ++ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) { ++ rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n", ++ entry->entry_idx, qid); ++ break; ++ } ++ ++ match = rt2800_txdone_entry_check(entry, reg); ++ rt2800_txdone_entry(entry, reg, rt2800_drv_get_txwi(entry), match); ++ } ++} ++EXPORT_SYMBOL_GPL(rt2800_txdone); ++ ++static inline bool rt2800_entry_txstatus_timeout(struct queue_entry *entry) ++{ ++ bool tout; ++ ++ if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) ++ return false; ++ ++ tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(500)); ++ if (unlikely(tout)) ++ rt2x00_dbg(entry->queue->rt2x00dev, ++ "TX status timeout for entry %d in queue %d\n", ++ entry->entry_idx, entry->queue->qid); ++ return tout; ++ ++} ++ ++bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev) ++{ ++ struct data_queue *queue; ++ struct queue_entry *entry; ++ ++ tx_queue_for_each(rt2x00dev, queue) { ++ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); ++ if (rt2800_entry_txstatus_timeout(entry)) ++ return true; ++ } ++ return false; ++} ++EXPORT_SYMBOL_GPL(rt2800_txstatus_timeout); ++ ++void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev) ++{ ++ struct data_queue *queue; ++ struct queue_entry *entry; ++ ++ /* ++ * Process any trailing TX status reports for IO failures, ++ * we loop until we find the first non-IO error entry. This ++ * can either be a frame which is free, is being uploaded, ++ * or has completed the upload but didn't have an entry ++ * in the TX_STAT_FIFO register yet. ++ */ ++ tx_queue_for_each(rt2x00dev, queue) { ++ while (!rt2x00queue_empty(queue)) { ++ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); ++ ++ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || ++ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) ++ break; ++ ++ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) || ++ rt2800_entry_txstatus_timeout(entry)) ++ rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); ++ else ++ break; ++ } ++ } ++} ++EXPORT_SYMBOL_GPL(rt2800_txdone_nostatus); ++ + static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev, + unsigned int index) + { +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +@@ -195,6 +195,9 @@ void rt2800_process_rxwi(struct queue_en + + void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, + bool match); ++void rt2800_txdone(struct rt2x00_dev *rt2x00dev); ++void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev); ++bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev); + + void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); + void rt2800_clear_beacon(struct queue_entry *entry); +--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +@@ -116,35 +116,6 @@ static bool rt2800usb_txstatus_pending(s + return false; + } + +-static inline bool rt2800usb_entry_txstatus_timeout(struct queue_entry *entry) +-{ +- bool tout; +- +- if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) +- return false; +- +- tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(500)); +- if (unlikely(tout)) +- rt2x00_dbg(entry->queue->rt2x00dev, +- "TX status timeout for entry %d in queue %d\n", +- entry->entry_idx, entry->queue->qid); +- return tout; +- +-} +- +-static bool rt2800usb_txstatus_timeout(struct rt2x00_dev *rt2x00dev) +-{ +- struct data_queue *queue; +- struct queue_entry *entry; +- +- tx_queue_for_each(rt2x00dev, queue) { +- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); +- if (rt2800usb_entry_txstatus_timeout(entry)) +- return true; +- } +- return false; +-} +- + #define TXSTATUS_READ_INTERVAL 1000000 + + static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, +@@ -171,7 +142,7 @@ static bool rt2800usb_tx_sta_fifo_read_c + } + + /* Check if there is any entry that timedout waiting on TX status */ +- if (rt2800usb_txstatus_timeout(rt2x00dev)) ++ if (rt2800_txstatus_timeout(rt2x00dev)) + queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); + + if (rt2800usb_txstatus_pending(rt2x00dev)) { +@@ -501,123 +472,17 @@ static int rt2800usb_get_tx_data_len(str + /* + * TX control handlers + */ +-static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) +-{ +- __le32 *txwi; +- u32 word; +- int wcid, ack, pid; +- int tx_wcid, tx_ack, tx_pid, is_agg; +- +- /* +- * This frames has returned with an IO error, +- * so the status report is not intended for this +- * frame. +- */ +- if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) +- return false; +- +- wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); +- ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); +- pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); +- is_agg = rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE); +- +- /* +- * Validate if this TX status report is intended for +- * this entry by comparing the WCID/ACK/PID fields. +- */ +- txwi = rt2800usb_get_txwi(entry); +- +- word = rt2x00_desc_read(txwi, 1); +- tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); +- tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); +- tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); +- +- if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) { +- rt2x00_dbg(entry->queue->rt2x00dev, +- "TX status report missed for queue %d entry %d\n", +- entry->queue->qid, entry->entry_idx); +- return false; +- } +- +- return true; +-} +- +-static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) +-{ +- struct data_queue *queue; +- struct queue_entry *entry; +- u32 reg; +- u8 qid; +- bool match; +- +- while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { +- /* +- * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is +- * guaranteed to be one of the TX QIDs . +- */ +- qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); +- queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); +- +- if (unlikely(rt2x00queue_empty(queue))) { +- rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n", +- qid); +- break; +- } +- +- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); +- +- if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || +- !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) { +- rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n", +- entry->entry_idx, qid); +- break; +- } +- +- match = rt2800usb_txdone_entry_check(entry, reg); +- rt2800_txdone_entry(entry, reg, rt2800usb_get_txwi(entry), match); +- } +-} +- +-static void rt2800usb_txdone_nostatus(struct rt2x00_dev *rt2x00dev) +-{ +- struct data_queue *queue; +- struct queue_entry *entry; +- +- /* +- * Process any trailing TX status reports for IO failures, +- * we loop until we find the first non-IO error entry. This +- * can either be a frame which is free, is being uploaded, +- * or has completed the upload but didn't have an entry +- * in the TX_STAT_FIFO register yet. +- */ +- tx_queue_for_each(rt2x00dev, queue) { +- while (!rt2x00queue_empty(queue)) { +- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); +- +- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || +- !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) +- break; +- +- if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) || +- rt2800usb_entry_txstatus_timeout(entry)) +- rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); +- else +- break; +- } +- } +-} +- + static void rt2800usb_work_txdone(struct work_struct *work) + { + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, txdone_work); + + while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) || +- rt2800usb_txstatus_timeout(rt2x00dev)) { ++ rt2800_txstatus_timeout(rt2x00dev)) { + +- rt2800usb_txdone(rt2x00dev); ++ rt2800_txdone(rt2x00dev); + +- rt2800usb_txdone_nostatus(rt2x00dev); ++ rt2800_txdone_nostatus(rt2x00dev); + + /* + * The hw may delay sending the packet after DMA complete -- cgit v1.2.3