diff options
author | Daniel Golle <daniel@makrotopia.org> | 2018-08-15 16:02:18 +0200 |
---|---|---|
committer | John Crispin <john@phrozen.org> | 2018-09-26 16:39:44 +0200 |
commit | de1c58a64bd66319e770d2587da07d8c9c90174a (patch) | |
tree | 5e604fc51a2bd53afbf858f18f00bcf821199a46 /package/kernel/mac80211/patches/rt2x00/701-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch | |
parent | c837c41a768ddd6f3d028fe480dd972b40389b2a (diff) | |
download | upstream-de1c58a64bd66319e770d2587da07d8c9c90174a.tar.gz upstream-de1c58a64bd66319e770d2587da07d8c9c90174a.tar.bz2 upstream-de1c58a64bd66319e770d2587da07d8c9c90174a.zip |
mac80211: rt2x00: add experimental patches from Stanislaw Gruszka
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Diffstat (limited to 'package/kernel/mac80211/patches/rt2x00/701-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch')
-rw-r--r-- | package/kernel/mac80211/patches/rt2x00/701-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/rt2x00/701-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch b/package/kernel/mac80211/patches/rt2x00/701-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch new file mode 100644 index 0000000000..5d69b5db30 --- /dev/null +++ b/package/kernel/mac80211/patches/rt2x00/701-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch @@ -0,0 +1,365 @@ +From 0381bfbc400ce4c3000b0b31c577ad9e8071e4f6 Mon Sep 17 00:00:00 2001 +From: Stanislaw Gruszka <sgruszka@redhat.com> +Date: Fri, 18 May 2018 12:25:08 +0200 +Subject: [PATCH 1/5] 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 <sgruszka@redhat.com> +--- + .../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(-) + +diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +index a567bc273ffc..9f2835729016 100644 +--- 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(struct skb_frame_desc *skbdesc, + 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_entry *entry, u32 status, __le32 *txwi, + } + 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) + { +diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +index 51d9c2a932cc..0dff2c7b3010 100644 +--- 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_entry *entry, struct rxdone_entry_desc *tx + + 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); +diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +index 98a7313fea4a..19eabf16147b 100644 +--- 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(struct rt2x00_dev *rt2x00dev) + 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_completed(struct rt2x00_dev *rt2x00dev, + } + + /* 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(struct queue_entry *entry) + /* + * 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 +-- +2.18.0 + |