aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/rt2x00/701-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch
diff options
context:
space:
mode:
authorDaniel Golle <daniel@makrotopia.org>2018-08-15 16:02:18 +0200
committerJohn Crispin <john@phrozen.org>2018-09-26 16:39:44 +0200
commitde1c58a64bd66319e770d2587da07d8c9c90174a (patch)
tree5e604fc51a2bd53afbf858f18f00bcf821199a46 /package/kernel/mac80211/patches/rt2x00/701-rt2800-move-usb-specific-txdone-txstatus-routines-to.patch
parentc837c41a768ddd6f3d028fe480dd972b40389b2a (diff)
downloadupstream-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.patch365
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, &reg)) {
++ /*
++ * 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, &reg)) {
+- /*
+- * 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
+