Initial commit

This commit is contained in:
domenico
2025-06-24 16:03:39 +02:00
commit f3256cdaf2
6949 changed files with 1441681 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
From f483039cf51acf30494cd754194562c22cf98764 Mon Sep 17 00:00:00 2001
From: Dan Carpenter <dan.carpenter@oracle.com>
Date: Wed, 22 Aug 2018 13:41:26 +0300
Subject: [PATCH 01/28] rt2x00: use simple_read_from_buffer()
The problem with this copy_to_user() calls is that they don't ensure
that "size" is less than the "length" which the user provided.
Obviously, this is debugfs and "size" is normally going to be very small
so it probably doesn't matter, but this is the correct thing to do.
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2x00debug.c | 18 +++---------------
1 file changed, 3 insertions(+), 15 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
@@ -464,11 +464,7 @@ static ssize_t rt2x00debug_read_##__name
\
size = sprintf(line, __format, value); \
\
- if (copy_to_user(buf, line, size)) \
- return -EFAULT; \
- \
- *offset += size; \
- return size; \
+ return simple_read_from_buffer(buf, length, offset, line, size); \
}
#define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \
@@ -545,11 +541,7 @@ static ssize_t rt2x00debug_read_dev_flag
size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags);
- if (copy_to_user(buf, line, size))
- return -EFAULT;
-
- *offset += size;
- return size;
+ return simple_read_from_buffer(buf, length, offset, line, size);
}
static const struct file_operations rt2x00debug_fop_dev_flags = {
@@ -574,11 +566,7 @@ static ssize_t rt2x00debug_read_cap_flag
size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags);
- if (copy_to_user(buf, line, size))
- return -EFAULT;
-
- *offset += size;
- return size;
+ return simple_read_from_buffer(buf, length, offset, line, size);
}
static const struct file_operations rt2x00debug_fop_cap_flags = {

View File

@@ -0,0 +1,357 @@
From 5c656c71b1bf5611ce8262bab338104e04d10b8d Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
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 <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../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, &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)
{
--- 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, &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

View File

@@ -0,0 +1,244 @@
From 0b0d556e0ebb6c966bc993e21a22a156812d8fdf Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Wed, 26 Sep 2018 12:24:54 +0200
Subject: [PATCH 03/28] rt2800mmio: use txdone/txstatus routines from lib
Use usb txdone/txstatus routines (now in rt2800libc) for mmio devices.
Note this also change how we handle INT_SOURCE_CSR_TX_FIFO_STATUS
interrupt. Now it is disabled since IRQ routine till end of the txstatus
tasklet (the same behaviour like others interrupts). Reason to do not
disable this interrupt was not to miss any tx status from 16 entries
FIFO register. Now, since we check for tx status timeout, we can
allow to miss some tx statuses. However this will be improved in further
patch where I also implement read status FIFO register in the tasklet.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2800mmio.c | 180 +-----------------
.../net/wireless/ralink/rt2x00/rt2x00queue.c | 1 +
2 files changed, 9 insertions(+), 172 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
@@ -175,161 +175,6 @@ static void rt2800mmio_wakeup(struct rt2
rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
}
-static bool rt2800mmio_txdone_entry_check(struct queue_entry *entry, u32 status)
-{
- __le32 *txwi;
- u32 word;
- int wcid, tx_wcid;
-
- wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID);
-
- txwi = rt2800_drv_get_txwi(entry);
- word = rt2x00_desc_read(txwi, 1);
- tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
-
- return (tx_wcid == wcid);
-}
-
-static bool rt2800mmio_txdone_find_entry(struct queue_entry *entry, void *data)
-{
- u32 status = *(u32 *)data;
-
- /*
- * rt2800pci hardware might reorder frames when exchanging traffic
- * with multiple BA enabled STAs.
- *
- * For example, a tx queue
- * [ STA1 | STA2 | STA1 | STA2 ]
- * can result in tx status reports
- * [ STA1 | STA1 | STA2 | STA2 ]
- * when the hw decides to aggregate the frames for STA1 into one AMPDU.
- *
- * To mitigate this effect, associate the tx status to the first frame
- * in the tx queue with a matching wcid.
- */
- if (rt2800mmio_txdone_entry_check(entry, status) &&
- !test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
- /*
- * Got a matching frame, associate the tx status with
- * the frame
- */
- entry->status = status;
- set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
- return true;
- }
-
- /* Check the next frame */
- return false;
-}
-
-static bool rt2800mmio_txdone_match_first(struct queue_entry *entry, void *data)
-{
- u32 status = *(u32 *)data;
-
- /*
- * Find the first frame without tx status and assign this status to it
- * regardless if it matches or not.
- */
- if (!test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
- /*
- * Got a matching frame, associate the tx status with
- * the frame
- */
- entry->status = status;
- set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
- return true;
- }
-
- /* Check the next frame */
- return false;
-}
-static bool rt2800mmio_txdone_release_entries(struct queue_entry *entry,
- void *data)
-{
- if (test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
- rt2800_txdone_entry(entry, entry->status,
- rt2800mmio_get_txwi(entry), true);
- return false;
- }
-
- /* No more frames to release */
- return true;
-}
-
-static bool rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
- u32 status;
- u8 qid;
- int max_tx_done = 16;
-
- while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) {
- qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE);
- if (unlikely(qid >= QID_RX)) {
- /*
- * Unknown queue, this shouldn't happen. Just drop
- * this tx status.
- */
- rt2x00_warn(rt2x00dev, "Got TX status report with unexpected pid %u, dropping\n",
- qid);
- break;
- }
-
- queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
- if (unlikely(queue == NULL)) {
- /*
- * The queue is NULL, this shouldn't happen. Stop
- * processing here and drop the tx status
- */
- rt2x00_warn(rt2x00dev, "Got TX status for an unavailable queue %u, dropping\n",
- qid);
- break;
- }
-
- if (unlikely(rt2x00queue_empty(queue))) {
- /*
- * The queue is empty. Stop processing here
- * and drop the tx status.
- */
- rt2x00_warn(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
- qid);
- break;
- }
-
- /*
- * Let's associate this tx status with the first
- * matching frame.
- */
- if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
- Q_INDEX, &status,
- rt2800mmio_txdone_find_entry)) {
- /*
- * We cannot match the tx status to any frame, so just
- * use the first one.
- */
- if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
- Q_INDEX, &status,
- rt2800mmio_txdone_match_first)) {
- rt2x00_warn(rt2x00dev, "No frame found for TX status on queue %u, dropping\n",
- qid);
- break;
- }
- }
-
- /*
- * Release all frames with a valid tx status.
- */
- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
- Q_INDEX, NULL,
- rt2800mmio_txdone_release_entries);
-
- if (--max_tx_done == 0)
- break;
- }
-
- return !max_tx_done;
-}
-
static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev,
struct rt2x00_field32 irq_field)
{
@@ -349,14 +194,14 @@ static inline void rt2800mmio_enable_int
void rt2800mmio_txstatus_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
- if (rt2800mmio_txdone(rt2x00dev))
- tasklet_schedule(&rt2x00dev->txstatus_tasklet);
- /*
- * No need to enable the tx status interrupt here as we always
- * leave it enabled to minimize the possibility of a tx status
- * register overflow. See comment in interrupt handler.
- */
+ rt2800_txdone(rt2x00dev);
+
+ rt2800_txdone_nostatus(rt2x00dev);
+
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt2800mmio_enable_interrupt(rt2x00dev,
+ INT_SOURCE_CSR_TX_FIFO_STATUS);
}
EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
@@ -440,10 +285,6 @@ static void rt2800mmio_txstatus_interrup
* because we can schedule the tasklet multiple times (when the
* interrupt fires again during tx status processing).
*
- * Furthermore we don't disable the TX_FIFO_STATUS
- * interrupt here but leave it enabled so that the TX_STA_FIFO
- * can also be read while the tx status tasklet gets executed.
- *
* Since we have only one producer and one consumer we don't
* need to lock the kfifo.
*/
@@ -485,13 +326,8 @@ irqreturn_t rt2800mmio_interrupt(int irq
*/
mask = ~reg;
- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
rt2800mmio_txstatus_interrupt(rt2x00dev);
- /*
- * Never disable the TX_FIFO_STATUS interrupt.
- */
- rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1);
- }
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet);
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
@@ -113,6 +113,7 @@ int rt2x00queue_map_txskb(struct queue_e
return -ENOMEM;
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
+ rt2x00lib_dmadone(entry);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);

View File

@@ -0,0 +1,72 @@
From 5022efb50f625d11fdf18b1fee0f64ebb1863664 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Wed, 26 Sep 2018 12:24:55 +0200
Subject: [PATCH 04/28] rt2x00: do not check for txstatus timeout every time on
tasklet
Do not check for tx status timeout everytime we perform txstatus tasklet.
Perform check once per half a second.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 7 +++++++
drivers/net/wireless/ralink/rt2x00/rt2800mmio.c | 3 ++-
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 2 ++
drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 1 +
4 files changed, 12 insertions(+), 1 deletion(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1158,11 +1158,18 @@ bool rt2800_txstatus_timeout(struct rt2x
struct data_queue *queue;
struct queue_entry *entry;
+ if (time_before(jiffies,
+ rt2x00dev->last_nostatus_check + msecs_to_jiffies(500)))
+ return false;
+
+ rt2x00dev->last_nostatus_check = jiffies;
+
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);
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
@@ -197,7 +197,8 @@ void rt2800mmio_txstatus_tasklet(unsigne
rt2800_txdone(rt2x00dev);
- rt2800_txdone_nostatus(rt2x00dev);
+ if (rt2800_txstatus_timeout(rt2x00dev))
+ rt2800_txdone_nostatus(rt2x00dev);
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2800mmio_enable_interrupt(rt2x00dev,
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -979,6 +979,8 @@ struct rt2x00_dev {
*/
DECLARE_KFIFO_PTR(txstatus_fifo, u32);
+ unsigned long last_nostatus_check;
+
/*
* Timer to ensure tx status reports are read (rt2800usb).
*/
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
@@ -1042,6 +1042,7 @@ void rt2x00queue_start_queues(struct rt2
*/
tx_queue_for_each(rt2x00dev, queue)
rt2x00queue_start_queue(queue);
+ rt2x00dev->last_nostatus_check = jiffies;
rt2x00queue_start_queue(rt2x00dev->rx);
}

View File

@@ -0,0 +1,112 @@
From adf26a356f132e35093585521ea3e36cd185af83 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Wed, 26 Sep 2018 12:24:56 +0200
Subject: [PATCH 05/28] rt2x00: use different txstatus timeouts when flushing
Use different tx status timeouts for normal operation and when flushing.
This increase timeout to 2s for normal operation as when there are bad
radio conditions and frames are reposted many times device can not provide
the status for quite long. With new timeout we can still get valid status
on such bad conditions.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 31 +++++++++++++------
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 +
.../net/wireless/ralink/rt2x00/rt2x00mac.c | 4 +++
3 files changed, 26 insertions(+), 10 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1137,36 +1137,47 @@ void rt2800_txdone(struct rt2x00_dev *rt
}
EXPORT_SYMBOL_GPL(rt2800_txdone);
-static inline bool rt2800_entry_txstatus_timeout(struct queue_entry *entry)
+static inline bool rt2800_entry_txstatus_timeout(struct rt2x00_dev *rt2x00dev,
+ struct queue_entry *entry)
{
- bool tout;
+ bool ret;
+ unsigned long 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))
+ if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags))
+ tout = msecs_to_jiffies(100);
+ else
+ tout = msecs_to_jiffies(2000);
+
+ ret = time_after(jiffies, entry->last_action + tout);
+ if (unlikely(ret))
rt2x00_dbg(entry->queue->rt2x00dev,
"TX status timeout for entry %d in queue %d\n",
entry->entry_idx, entry->queue->qid);
- return tout;
-
+ return ret;
}
bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
struct queue_entry *entry;
+ unsigned long tout;
+
+ if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags))
+ tout = msecs_to_jiffies(50);
+ else
+ tout = msecs_to_jiffies(1000);
- if (time_before(jiffies,
- rt2x00dev->last_nostatus_check + msecs_to_jiffies(500)))
+ if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout))
return false;
rt2x00dev->last_nostatus_check = jiffies;
tx_queue_for_each(rt2x00dev, queue) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- if (rt2800_entry_txstatus_timeout(entry))
+ if (rt2800_entry_txstatus_timeout(rt2x00dev, entry))
return true;
}
@@ -1195,7 +1206,7 @@ void rt2800_txdone_nostatus(struct rt2x0
break;
if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) ||
- rt2800_entry_txstatus_timeout(entry))
+ rt2800_entry_txstatus_timeout(rt2x00dev, entry))
rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
else
break;
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -665,6 +665,7 @@ enum rt2x00_state_flags {
DEVICE_STATE_STARTED,
DEVICE_STATE_ENABLED_RADIO,
DEVICE_STATE_SCANNING,
+ DEVICE_STATE_FLUSHING,
/*
* Driver configuration
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
@@ -710,8 +710,12 @@ void rt2x00mac_flush(struct ieee80211_hw
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return;
+ set_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags);
+
tx_queue_for_each(rt2x00dev, queue)
rt2x00queue_flush_queue(queue, drop);
+
+ clear_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags);
}
EXPORT_SYMBOL_GPL(rt2x00mac_flush);

View File

@@ -0,0 +1,238 @@
From 0240564430c0697d8fde3743d70346a922466b36 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Wed, 26 Sep 2018 12:24:57 +0200
Subject: [PATCH 06/28] rt2800: flush and txstatus rework for rt2800mmio
Implement custom rt2800mmio flush routine and change txstatus
routine to read TX_STA_FIFO also in the tasklet.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 14 +--
.../net/wireless/ralink/rt2x00/rt2800mmio.c | 118 +++++++++++++-----
.../net/wireless/ralink/rt2x00/rt2800mmio.h | 1 +
.../net/wireless/ralink/rt2x00/rt2800pci.c | 2 +-
4 files changed, 97 insertions(+), 38 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1147,7 +1147,7 @@ static inline bool rt2800_entry_txstatus
return false;
if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags))
- tout = msecs_to_jiffies(100);
+ tout = msecs_to_jiffies(50);
else
tout = msecs_to_jiffies(2000);
@@ -1163,15 +1163,13 @@ bool rt2800_txstatus_timeout(struct rt2x
{
struct data_queue *queue;
struct queue_entry *entry;
- unsigned long tout;
- if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags))
- tout = msecs_to_jiffies(50);
- else
- tout = msecs_to_jiffies(1000);
+ if (!test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags)) {
+ unsigned long tout = msecs_to_jiffies(1000);
- if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout))
- return false;
+ if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout))
+ return false;
+ }
rt2x00dev->last_nostatus_check = jiffies;
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
@@ -191,21 +191,6 @@ static inline void rt2800mmio_enable_int
spin_unlock_irq(&rt2x00dev->irqmask_lock);
}
-void rt2800mmio_txstatus_tasklet(unsigned long data)
-{
- struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
-
- rt2800_txdone(rt2x00dev);
-
- if (rt2800_txstatus_timeout(rt2x00dev))
- rt2800_txdone_nostatus(rt2x00dev);
-
- if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2800mmio_enable_interrupt(rt2x00dev,
- INT_SOURCE_CSR_TX_FIFO_STATUS);
-}
-EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
-
void rt2800mmio_pretbtt_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
@@ -270,12 +255,26 @@ void rt2800mmio_autowake_tasklet(unsigne
}
EXPORT_SYMBOL_GPL(rt2800mmio_autowake_tasklet);
-static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
+static void rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev)
+{
+ bool timeout = false;
+
+ while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) ||
+ (timeout = rt2800_txstatus_timeout(rt2x00dev))) {
+
+ rt2800_txdone(rt2x00dev);
+
+ if (timeout)
+ rt2800_txdone_nostatus(rt2x00dev);
+ }
+}
+
+static bool rt2800mmio_fetch_txstatus(struct rt2x00_dev *rt2x00dev)
{
u32 status;
- int i;
+ bool more = false;
- /*
+ /* FIXEME: rewrite this comment
* The TX_FIFO_STATUS interrupt needs special care. We should
* read TX_STA_FIFO but we should do it immediately as otherwise
* the register can overflow and we would lose status reports.
@@ -286,25 +285,37 @@ static void rt2800mmio_txstatus_interrup
* because we can schedule the tasklet multiple times (when the
* interrupt fires again during tx status processing).
*
- * Since we have only one producer and one consumer we don't
+ * txstatus tasklet is called with INT_SOURCE_CSR_TX_FIFO_STATUS
+ * disabled so have only one producer and one consumer - we don't
* need to lock the kfifo.
*/
- for (i = 0; i < rt2x00dev->tx->limit; i++) {
+ while (!kfifo_is_full(&rt2x00dev->txstatus_fifo)) {
status = rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO);
-
if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
break;
- if (!kfifo_put(&rt2x00dev->txstatus_fifo, status)) {
- rt2x00_warn(rt2x00dev, "TX status FIFO overrun, drop tx status report\n");
- break;
- }
+ kfifo_put(&rt2x00dev->txstatus_fifo, status);
+ more = true;
}
- /* Schedule the tasklet for processing the tx status. */
- tasklet_schedule(&rt2x00dev->txstatus_tasklet);
+ return more;
}
+void rt2800mmio_txstatus_tasklet(unsigned long data)
+{
+ struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
+
+ do {
+ rt2800mmio_txdone(rt2x00dev);
+
+ } while (rt2800mmio_fetch_txstatus(rt2x00dev));
+
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt2800mmio_enable_interrupt(rt2x00dev,
+ INT_SOURCE_CSR_TX_FIFO_STATUS);
+}
+EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
+
irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
@@ -327,8 +338,10 @@ irqreturn_t rt2800mmio_interrupt(int irq
*/
mask = ~reg;
- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
- rt2800mmio_txstatus_interrupt(rt2x00dev);
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
+ rt2800mmio_fetch_txstatus(rt2x00dev);
+ tasklet_schedule(&rt2x00dev->txstatus_tasklet);
+ }
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet);
@@ -453,6 +466,53 @@ void rt2800mmio_kick_queue(struct data_q
}
EXPORT_SYMBOL_GPL(rt2800mmio_kick_queue);
+void rt2800mmio_flush_queue(struct data_queue *queue, bool drop)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ bool tx_queue = false;
+ unsigned int i;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ tx_queue = true;
+ break;
+ case QID_RX:
+ break;
+ default:
+ return;
+ }
+
+ for (i = 0; i < 5; i++) {
+ /*
+ * Check if the driver is already done, otherwise we
+ * have to sleep a little while to give the driver/hw
+ * the oppurtunity to complete interrupt process itself.
+ */
+ if (rt2x00queue_empty(queue))
+ break;
+
+ /*
+ * For TX queues schedule completion tasklet to catch
+ * tx status timeouts, othewise just wait.
+ */
+ if (tx_queue) {
+ tasklet_disable(&rt2x00dev->txstatus_tasklet);
+ rt2800mmio_txdone(rt2x00dev);
+ tasklet_enable(&rt2x00dev->txstatus_tasklet);
+ }
+
+ /*
+ * Wait for a little while to give the driver
+ * the oppurtunity to recover itself.
+ */
+ msleep(50);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2800mmio_flush_queue);
+
void rt2800mmio_stop_queue(struct data_queue *queue)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
@@ -148,6 +148,7 @@ void rt2800mmio_toggle_irq(struct rt2x00
/* Queue handlers */
void rt2800mmio_start_queue(struct data_queue *queue);
void rt2800mmio_kick_queue(struct data_queue *queue);
+void rt2800mmio_flush_queue(struct data_queue *queue, bool drop);
void rt2800mmio_stop_queue(struct data_queue *queue);
void rt2800mmio_queue_init(struct data_queue *queue);
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -364,7 +364,7 @@ static const struct rt2x00lib_ops rt2800
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
- .flush_queue = rt2x00mmio_flush_queue,
+ .flush_queue = rt2800mmio_flush_queue,
.write_tx_desc = rt2800mmio_write_tx_desc,
.write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,

View File

@@ -0,0 +1,25 @@
From 6eba8fd2235237784dfd01da55c3210d493aebdb Mon Sep 17 00:00:00 2001
From: "Gustavo A. R. Silva" <gustavo@embeddedor.com>
Date: Mon, 22 Oct 2018 22:44:34 +0200
Subject: [PATCH 07/28] rt2x00: rt2400pci: mark expected switch fall-through
In preparation to enabling -Wimplicit-fallthrough, mark switch cases
where we are expecting to fall through.
Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
@@ -1302,7 +1302,7 @@ static void rt2400pci_txdone(struct rt2x
break;
case 2: /* Failure, excessive retries */
__set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
- /* Don't break, this is a failed frame! */
+ /* Fall through - this is a failed frame! */
default: /* Failure */
__set_bit(TXDONE_FAILURE, &txdesc.flags);
}

View File

@@ -0,0 +1,25 @@
From 10bb92217747c3384a01ebec005faa2f5e72bbd8 Mon Sep 17 00:00:00 2001
From: "Gustavo A. R. Silva" <gustavo@embeddedor.com>
Date: Mon, 22 Oct 2018 22:45:19 +0200
Subject: [PATCH 08/28] rt2x00: rt2500pci: mark expected switch fall-through
In preparation to enabling -Wimplicit-fallthrough, mark switch cases
where we are expecting to fall through.
Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2500pci.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
@@ -1430,7 +1430,7 @@ static void rt2500pci_txdone(struct rt2x
break;
case 2: /* Failure, excessive retries */
__set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
- /* Don't break, this is a failed frame! */
+ /* Fall through - this is a failed frame! */
default: /* Failure */
__set_bit(TXDONE_FAILURE, &txdesc.flags);
}

View File

@@ -0,0 +1,44 @@
From 916e6bbcfcff6cc5d7d33bba8557a30f3af50326 Mon Sep 17 00:00:00 2001
From: "Gustavo A. R. Silva" <gustavo@embeddedor.com>
Date: Mon, 22 Oct 2018 22:46:03 +0200
Subject: [PATCH 09/28] rt2x00: rt2800lib: mark expected switch fall-throughs
In preparation to enabling -Wimplicit-fallthrough, mark switch cases
where we are expecting to fall through.
Addresses-Coverity-ID: 145198 ("Missing break in switch")
Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -2482,6 +2482,7 @@ static void rt2800_config_channel_rf3052
switch (rt2x00dev->default_ant.tx_chain_num) {
case 1:
rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
+ /* fall through */
case 2:
rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1);
break;
@@ -2490,6 +2491,7 @@ static void rt2800_config_channel_rf3052
switch (rt2x00dev->default_ant.rx_chain_num) {
case 1:
rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
+ /* fall through */
case 2:
rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1);
break;
@@ -9457,8 +9459,10 @@ static int rt2800_probe_hw_mode(struct r
switch (rx_chains) {
case 3:
spec->ht.mcs.rx_mask[2] = 0xff;
+ /* fall through */
case 2:
spec->ht.mcs.rx_mask[1] = 0xff;
+ /* fall through */
case 1:
spec->ht.mcs.rx_mask[0] = 0xff;
spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */

View File

@@ -0,0 +1,25 @@
From 641dd8068ecb078e7d12efe465df202bc16ca5eb Mon Sep 17 00:00:00 2001
From: "Gustavo A. R. Silva" <gustavo@embeddedor.com>
Date: Mon, 22 Oct 2018 22:46:47 +0200
Subject: [PATCH 10/28] rt2x00: rt61pci: mark expected switch fall-through
In preparation to enabling -Wimplicit-fallthrough, mark switch cases
where we are expecting to fall through.
Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt61pci.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
@@ -2226,7 +2226,7 @@ static void rt61pci_txdone(struct rt2x00
break;
case 6: /* Failure, excessive retries */
__set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
- /* Don't break, this is a failed frame! */
+ /* Fall through - this is a failed frame! */
default: /* Failure */
__set_bit(TXDONE_FAILURE, &txdesc.flags);
}

View File

@@ -0,0 +1,40 @@
From 750afb08ca71310fcf0c4e2cb1565c63b8235b60 Mon Sep 17 00:00:00 2001
From: Luis Chamberlain <mcgrof@kernel.org>
Date: Fri, 4 Jan 2019 09:23:09 +0100
Subject: [PATCH 11/28] cross-tree: phase out dma_zalloc_coherent()
We already need to zero out memory for dma_alloc_coherent(), as such
using dma_zalloc_coherent() is superflous. Phase it out.
This change was generated with the following Coccinelle SmPL patch:
@ replace_dma_zalloc_coherent @
expression dev, size, data, handle, flags;
@@
-dma_zalloc_coherent(dev, size, handle, flags)
+dma_alloc_coherent(dev, size, handle, flags)
Suggested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
[hch: re-ran the script on the latest tree]
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c
@@ -119,9 +119,9 @@ static int rt2x00mmio_alloc_queue_dma(st
/*
* Allocate DMA memory for descriptor and buffer.
*/
- addr = dma_zalloc_coherent(rt2x00dev->dev,
- queue->limit * queue->desc_size, &dma,
- GFP_KERNEL);
+ addr = dma_alloc_coherent(rt2x00dev->dev,
+ queue->limit * queue->desc_size, &dma,
+ GFP_KERNEL);
if (!addr)
return -ENOMEM;

View File

@@ -0,0 +1,32 @@
From c2e28ef7711ffcb083474ee5f154264c6ec1ec07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomislav=20Po=C5=BEega?= <pozega.tomislav@gmail.com>
Date: Thu, 27 Dec 2018 15:05:25 +0100
Subject: [PATCH 12/28] rt2x00: reduce tx power to nominal level on RT6352
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Current implementation of RT6352 support provides too high tx power
at least on iPA/eLNA devices. Reduce amplification of variable gain
amplifier by 6dB to match board target power of 17dBm.
Transmited signal strength with this patch is similar to that of
stock firmware or pandorabox firmware. Throughput measured with iperf
improves. Device tested: Xiaomi Miwifi Mini.
Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -5477,7 +5477,7 @@ static int rt2800_init_registers(struct
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
rt2800_register_write(rt2x00dev, MIMO_PS_CFG, 0x00000002);
rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0x00150F0F);
- rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x06060606);
+ rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000);
rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0);
rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, 0x0);
rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN, 0x6C6C666C);

View File

@@ -0,0 +1,143 @@
From a4296994eb8061ee3455721a296c387c639bf635 Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Tue, 15 Jan 2019 14:01:29 +0000
Subject: [PATCH 13/28] rt2x00: Work around a firmware bug with shared keys
Apparently the rt2x61 firmware fails temporarily to decode
broadcast packets if the shared keys are not assigned
in the "correct" sequence. At the same time unicast
packets work fine, since they are encrypted with the
pairwise key.
At least with WPA2 CCMP mode the shared keys are
set in the following sequence: keyidx=1, 2, 1, 2.
After a while only keyidx 2 gets decrypted, and
keyidx 1 is ignored, probably because there is never
a keyidx 3.
Symptoms are arping -b works for 10 minutes, since
keyidx=2 is used for broadcast, and then it stops
working for 10 minutes, because keyidx=1 is used.
That failure mode repeats forever.
Note, the firmware does not even know which keyidx
corresponds to which hw_key_idx so the firmware is
trying to be smarter than the driver, which is bound
to fail.
As workaround the function rt61pci_config_shared_key
requests software decryption of the shared keys,
by returning EOPNOTSUPP. However, pairwise keys are
still handled by hardware which works just fine.
Signed-off-by: Bernd Edlinger <bernd.edlinger@hotmail.de>
Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt61pci.c | 93 +-------------------
1 file changed, 4 insertions(+), 89 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
@@ -321,97 +321,12 @@ static int rt61pci_config_shared_key(str
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key)
{
- struct hw_key_entry key_entry;
- struct rt2x00_field32 field;
- u32 mask;
- u32 reg;
-
- if (crypto->cmd == SET_KEY) {
- /*
- * rt2x00lib can't determine the correct free
- * key_idx for shared keys. We have 1 register
- * with key valid bits. The goal is simple, read
- * the register, if that is full we have no slots
- * left.
- * Note that each BSS is allowed to have up to 4
- * shared keys, so put a mask over the allowed
- * entries.
- */
- mask = (0xf << crypto->bssidx);
-
- reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR0);
- reg &= mask;
-
- if (reg && reg == mask)
- return -ENOSPC;
-
- key->hw_key_idx += reg ? ffz(reg) : 0;
-
- /*
- * Upload key to hardware
- */
- memcpy(key_entry.key, crypto->key,
- sizeof(key_entry.key));
- memcpy(key_entry.tx_mic, crypto->tx_mic,
- sizeof(key_entry.tx_mic));
- memcpy(key_entry.rx_mic, crypto->rx_mic,
- sizeof(key_entry.rx_mic));
-
- reg = SHARED_KEY_ENTRY(key->hw_key_idx);
- rt2x00mmio_register_multiwrite(rt2x00dev, reg,
- &key_entry, sizeof(key_entry));
-
- /*
- * The cipher types are stored over 2 registers.
- * bssidx 0 and 1 keys are stored in SEC_CSR1 and
- * bssidx 1 and 2 keys are stored in SEC_CSR5.
- * Using the correct defines correctly will cause overhead,
- * so just calculate the correct offset.
- */
- if (key->hw_key_idx < 8) {
- field.bit_offset = (3 * key->hw_key_idx);
- field.bit_mask = 0x7 << field.bit_offset;
-
- reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR1);
- rt2x00_set_field32(&reg, field, crypto->cipher);
- rt2x00mmio_register_write(rt2x00dev, SEC_CSR1, reg);
- } else {
- field.bit_offset = (3 * (key->hw_key_idx - 8));
- field.bit_mask = 0x7 << field.bit_offset;
-
- reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR5);
- rt2x00_set_field32(&reg, field, crypto->cipher);
- rt2x00mmio_register_write(rt2x00dev, SEC_CSR5, reg);
- }
-
- /*
- * The driver does not support the IV/EIV generation
- * in hardware. However it doesn't support the IV/EIV
- * inside the ieee80211 frame either, but requires it
- * to be provided separately for the descriptor.
- * rt2x00lib will cut the IV/EIV data out of all frames
- * given to us by mac80211, but we must tell mac80211
- * to generate the IV/EIV data.
- */
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- }
-
/*
- * SEC_CSR0 contains only single-bit fields to indicate
- * a particular key is valid. Because using the FIELD32()
- * defines directly will cause a lot of overhead, we use
- * a calculation to determine the correct bit directly.
+ * Let the software handle the shared keys,
+ * since the hardware decryption does not work reliably,
+ * because the firmware does not know the key's keyidx.
*/
- mask = 1 << key->hw_key_idx;
-
- reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR0);
- if (crypto->cmd == SET_KEY)
- reg |= mask;
- else if (crypto->cmd == DISABLE_KEY)
- reg &= ~mask;
- rt2x00mmio_register_write(rt2x00dev, SEC_CSR0, reg);
-
- return 0;
+ return -EOPNOTSUPP;
}
static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,

View File

@@ -0,0 +1,107 @@
From 2587791d57588562c21e5ef7e678f02ab2f3eb82 Mon Sep 17 00:00:00 2001
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: Tue, 22 Jan 2019 16:21:34 +0100
Subject: [PATCH 14/28] rt2x00: no need to check return value of debugfs_create
functions
When calling debugfs functions, there is no need to ever check the
return value. The function can work or not, but the code logic should
never do something different based on this.
Cc: Stanislaw Gruszka <sgruszka@redhat.com>
Cc: Helmut Schaa <helmut.schaa@googlemail.com>
Cc: Kalle Valo <kvalo@codeaurora.org>
Cc: linux-wireless@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2x00debug.c | 27 -------------------
1 file changed, 27 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
@@ -656,36 +656,24 @@ void rt2x00debug_register(struct rt2x00_
intf->driver_folder =
debugfs_create_dir(intf->rt2x00dev->ops->name,
rt2x00dev->hw->wiphy->debugfsdir);
- if (IS_ERR(intf->driver_folder) || !intf->driver_folder)
- goto exit;
intf->driver_entry =
rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);
- if (IS_ERR(intf->driver_entry) || !intf->driver_entry)
- goto exit;
intf->chipset_entry =
rt2x00debug_create_file_chipset("chipset",
intf, &intf->chipset_blob);
- if (IS_ERR(intf->chipset_entry) || !intf->chipset_entry)
- goto exit;
intf->dev_flags = debugfs_create_file("dev_flags", 0400,
intf->driver_folder, intf,
&rt2x00debug_fop_dev_flags);
- if (IS_ERR(intf->dev_flags) || !intf->dev_flags)
- goto exit;
intf->cap_flags = debugfs_create_file("cap_flags", 0400,
intf->driver_folder, intf,
&rt2x00debug_fop_cap_flags);
- if (IS_ERR(intf->cap_flags) || !intf->cap_flags)
- goto exit;
intf->register_folder =
debugfs_create_dir("register", intf->driver_folder);
- if (IS_ERR(intf->register_folder) || !intf->register_folder)
- goto exit;
#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \
({ \
@@ -695,9 +683,6 @@ void rt2x00debug_register(struct rt2x00_
0600, \
(__intf)->register_folder, \
&(__intf)->offset_##__name); \
- if (IS_ERR((__intf)->__name##_off_entry) || \
- !(__intf)->__name##_off_entry) \
- goto exit; \
\
(__intf)->__name##_val_entry = \
debugfs_create_file(__stringify(__name) "_value", \
@@ -705,9 +690,6 @@ void rt2x00debug_register(struct rt2x00_
(__intf)->register_folder, \
(__intf), \
&rt2x00debug_fop_##__name); \
- if (IS_ERR((__intf)->__name##_val_entry) || \
- !(__intf)->__name##_val_entry) \
- goto exit; \
} \
})
@@ -721,15 +703,10 @@ void rt2x00debug_register(struct rt2x00_
intf->queue_folder =
debugfs_create_dir("queue", intf->driver_folder);
- if (IS_ERR(intf->queue_folder) || !intf->queue_folder)
- goto exit;
intf->queue_frame_dump_entry =
debugfs_create_file("dump", 0400, intf->queue_folder,
intf, &rt2x00debug_fop_queue_dump);
- if (IS_ERR(intf->queue_frame_dump_entry)
- || !intf->queue_frame_dump_entry)
- goto exit;
skb_queue_head_init(&intf->frame_dump_skbqueue);
init_waitqueue_head(&intf->frame_dump_waitqueue);
@@ -747,10 +724,6 @@ void rt2x00debug_register(struct rt2x00_
#endif
return;
-
-exit:
- rt2x00debug_deregister(rt2x00dev);
- rt2x00_err(rt2x00dev, "Failed to register debug handler\n");
}
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)

View File

@@ -0,0 +1,137 @@
From 17ae2acd1a6f5148edd80d84194e5d7c80be360e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomislav=20Po=C5=BEega?= <pozega.tomislav@gmail.com>
Date: Wed, 13 Feb 2019 11:09:12 +0100
Subject: [PATCH 15/28] rt2x00: remove unneeded check
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Remove band check from rf53xx channel config routine since all chips
using it are single band.
Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 103 +++++++++---------
1 file changed, 50 insertions(+), 53 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -2966,6 +2966,7 @@ static void rt2800_config_channel_rf53xx
struct channel_info *info)
{
u8 rfcsr;
+ int idx = rf->channel-1;
rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3);
@@ -3003,60 +3004,56 @@ static void rt2800_config_channel_rf53xx
rt2800_freq_cal_mode1(rt2x00dev);
- if (rf->channel <= 14) {
- int idx = rf->channel-1;
+ if (rt2x00_has_cap_bt_coexist(rt2x00dev)) {
+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
+ /* r55/r59 value array of channel 1~14 */
+ static const char r55_bt_rev[] = {0x83, 0x83,
+ 0x83, 0x73, 0x73, 0x63, 0x53, 0x53,
+ 0x53, 0x43, 0x43, 0x43, 0x43, 0x43};
+ static const char r59_bt_rev[] = {0x0e, 0x0e,
+ 0x0e, 0x0e, 0x0e, 0x0b, 0x0a, 0x09,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07};
+
+ rt2800_rfcsr_write(rt2x00dev, 55,
+ r55_bt_rev[idx]);
+ rt2800_rfcsr_write(rt2x00dev, 59,
+ r59_bt_rev[idx]);
+ } else {
+ static const char r59_bt[] = {0x8b, 0x8b, 0x8b,
+ 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x89,
+ 0x88, 0x88, 0x86, 0x85, 0x84};
- if (rt2x00_has_cap_bt_coexist(rt2x00dev)) {
- if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
- /* r55/r59 value array of channel 1~14 */
- static const char r55_bt_rev[] = {0x83, 0x83,
- 0x83, 0x73, 0x73, 0x63, 0x53, 0x53,
- 0x53, 0x43, 0x43, 0x43, 0x43, 0x43};
- static const char r59_bt_rev[] = {0x0e, 0x0e,
- 0x0e, 0x0e, 0x0e, 0x0b, 0x0a, 0x09,
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x07};
-
- rt2800_rfcsr_write(rt2x00dev, 55,
- r55_bt_rev[idx]);
- rt2800_rfcsr_write(rt2x00dev, 59,
- r59_bt_rev[idx]);
- } else {
- static const char r59_bt[] = {0x8b, 0x8b, 0x8b,
- 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x89,
- 0x88, 0x88, 0x86, 0x85, 0x84};
+ rt2800_rfcsr_write(rt2x00dev, 59, r59_bt[idx]);
+ }
+ } else {
+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
+ static const char r55_nonbt_rev[] = {0x23, 0x23,
+ 0x23, 0x23, 0x13, 0x13, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03};
+ static const char r59_nonbt_rev[] = {0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x06, 0x05, 0x04, 0x04};
+
+ rt2800_rfcsr_write(rt2x00dev, 55,
+ r55_nonbt_rev[idx]);
+ rt2800_rfcsr_write(rt2x00dev, 59,
+ r59_nonbt_rev[idx]);
+ } else if (rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392) ||
+ rt2x00_rt(rt2x00dev, RT6352)) {
+ static const char r59_non_bt[] = {0x8f, 0x8f,
+ 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8d,
+ 0x8a, 0x88, 0x88, 0x87, 0x87, 0x86};
+
+ rt2800_rfcsr_write(rt2x00dev, 59,
+ r59_non_bt[idx]);
+ } else if (rt2x00_rt(rt2x00dev, RT5350)) {
+ static const char r59_non_bt[] = {0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a,
+ 0x0a, 0x09, 0x08, 0x07, 0x07, 0x06};
- rt2800_rfcsr_write(rt2x00dev, 59, r59_bt[idx]);
- }
- } else {
- if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
- static const char r55_nonbt_rev[] = {0x23, 0x23,
- 0x23, 0x23, 0x13, 0x13, 0x03, 0x03,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03};
- static const char r59_nonbt_rev[] = {0x07, 0x07,
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x06, 0x05, 0x04, 0x04};
-
- rt2800_rfcsr_write(rt2x00dev, 55,
- r55_nonbt_rev[idx]);
- rt2800_rfcsr_write(rt2x00dev, 59,
- r59_nonbt_rev[idx]);
- } else if (rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392) ||
- rt2x00_rt(rt2x00dev, RT6352)) {
- static const char r59_non_bt[] = {0x8f, 0x8f,
- 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8d,
- 0x8a, 0x88, 0x88, 0x87, 0x87, 0x86};
-
- rt2800_rfcsr_write(rt2x00dev, 59,
- r59_non_bt[idx]);
- } else if (rt2x00_rt(rt2x00dev, RT5350)) {
- static const char r59_non_bt[] = {0x0b, 0x0b,
- 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a,
- 0x0a, 0x09, 0x08, 0x07, 0x07, 0x06};
-
- rt2800_rfcsr_write(rt2x00dev, 59,
- r59_non_bt[idx]);
- }
+ rt2800_rfcsr_write(rt2x00dev, 59,
+ r59_non_bt[idx]);
}
}
}

View File

@@ -0,0 +1,34 @@
From 5991a2ecd070ce5ef646b4e8e0bc8d99110604ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomislav=20Po=C5=BEega?= <pozega.tomislav@gmail.com>
Date: Wed, 13 Feb 2019 11:09:13 +0100
Subject: [PATCH 16/28] rt2x00: remove confusing AGC register
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Register 66 was causing issues on RT6352 if set to the same value as
in MTK driver. With 1c reg value device was working fine in both HT20
and HT40 modes.
Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -3983,11 +3983,7 @@ static void rt2800_config_channel(struct
rt2800_bbp_write(rt2x00dev, 196, reg);
/* AGC init */
- if (rt2x00_rt(rt2x00dev, RT6352))
- reg = 0x04;
- else
- reg = rf->channel <= 14 ? 0x1c : 0x24;
-
+ reg = rf->channel <= 14 ? 0x1c : 0x24;
reg += 2 * rt2x00dev->lna_gain;
rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg);

View File

@@ -0,0 +1,47 @@
From 9ad3b55654455258a9463384edb40077439d879f Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Wed, 13 Feb 2019 11:09:14 +0100
Subject: [PATCH 17/28] rt2800: enable TX_PIN_CFG_LNA_PE_ bits per band
Do not enable TX_PIN_CFG_LNA_PE_A* bits for 2.4GHz band and
vice versa TX_PIN_CFG_LNA_PE_G* bits for 5GHz.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -3893,18 +3893,24 @@ static void rt2800_config_channel(struct
switch (rt2x00dev->default_ant.rx_chain_num) {
case 3:
/* Turn on tertiary LNAs */
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A2_EN, 1);
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G2_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A2_EN,
+ rf->channel > 14);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G2_EN,
+ rf->channel <= 14);
/* fall-through */
case 2:
/* Turn on secondary LNAs */
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1);
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN,
+ rf->channel > 14);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN,
+ rf->channel <= 14);
/* fall-through */
case 1:
/* Turn on primary LNAs */
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1);
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN,
+ rf->channel > 14);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN,
+ rf->channel <= 14);
break;
}

View File

@@ -0,0 +1,41 @@
From 7aca14885edeab536a8cbe1e7cfeadd4c3310b9b Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Wed, 13 Feb 2019 11:09:15 +0100
Subject: [PATCH 18/28] rt2800: enable TX_PIN_CFG_RFRX_EN only for MT7620
The TX_PIN_CFG_RFRX_EN bit was not set on other devices than MT7620,
restore old behavaviour since setting this bit maight not be
correct for older devices.
Fixes: 41977e86c984 ("rt2x00: add support for MT7620")
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -3858,10 +3858,12 @@ static void rt2800_config_channel(struct
if (rt2x00_rt(rt2x00dev, RT3572))
rt2800_rfcsr_write(rt2x00dev, 8, 0);
- if (rt2x00_rt(rt2x00dev, RT6352))
+ if (rt2x00_rt(rt2x00dev, RT6352)) {
tx_pin = rt2800_register_read(rt2x00dev, TX_PIN_CFG);
- else
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFRX_EN, 1);
+ } else {
tx_pin = 0;
+ }
switch (rt2x00dev->default_ant.tx_chain_num) {
case 3:
@@ -3916,7 +3918,6 @@ static void rt2800_config_channel(struct
rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1);
rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1);
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFRX_EN, 1); /* mt7620 */
rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);

View File

@@ -0,0 +1,33 @@
From c7ff1bfeaf1ca69e3e401be211b55d1738d0c5fc Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Wed, 13 Feb 2019 11:09:16 +0100
Subject: [PATCH 19/28] rt2800: comment and simplify AGC init for RT6352
We do not need separate lines for calculating register values.
Also add comment that value is different than in vendor driver.
Suggested-by: Daniel Golle <daniel@makrotopia.org>
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -3989,9 +3989,12 @@ static void rt2800_config_channel(struct
rt2800_bbp_write(rt2x00dev, 195, 141);
rt2800_bbp_write(rt2x00dev, 196, reg);
- /* AGC init */
- reg = rf->channel <= 14 ? 0x1c : 0x24;
- reg += 2 * rt2x00dev->lna_gain;
+ /* AGC init.
+ * Despite the vendor driver using different values here for
+ * RT6352 chip, we use 0x1c for now. This may have to be changed
+ * once TSSI got implemented.
+ */
+ reg = (rf->channel <= 14 ? 0x1c : 0x24) + 2*rt2x00dev->lna_gain;
rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg);
rt2800_iq_calibrate(rt2x00dev, rf->channel);

View File

@@ -0,0 +1,39 @@
From patchwork Tue Mar 12 09:51:40 2019
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10848957
X-Patchwork-Delegate: johannes@sipsolutions.net
From: Stanislaw Gruszka <sgruszka@redhat.com>
To: linux-wireless@vger.kernel.org
Cc: =?utf-8?q?Tomislav_Po=C5=BEega?= <pozega.tomislav@gmail.com>,
Daniel Golle <daniel@makrotopia.org>, Felix Fietkau <nbd@nbd.name>,
Mathias Kresin <dev@kresin.me>
Subject: [PATCH v3 1/4] cfg80211: add ratelimited variants of err and warn
Date: Tue, 12 Mar 2019 10:51:40 +0100
Message-Id: <1552384303-29529-2-git-send-email-sgruszka@redhat.com>
In-Reply-To: <1552384303-29529-1-git-send-email-sgruszka@redhat.com>
References: <1552384303-29529-1-git-send-email-sgruszka@redhat.com>
wiphy_{err,warn}_ratelimited will be used by rt2x00
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
include/net/cfg80211.h | 5 +++++
1 file changed, 5 insertions(+)
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -6632,6 +6632,11 @@ bool cfg80211_iftype_allowed(struct wiph
#define wiphy_info(wiphy, format, args...) \
dev_info(&(wiphy)->dev, format, ##args)
+#define wiphy_err_ratelimited(wiphy, format, args...) \
+ dev_err_ratelimited(&(wiphy)->dev, format, ##args)
+#define wiphy_warn_ratelimited(wiphy, format, args...) \
+ dev_warn_ratelimited(&(wiphy)->dev, format, ##args)
+
#define wiphy_debug(wiphy, format, args...) \
wiphy_printk(KERN_DEBUG, wiphy, format, ##args)

View File

@@ -0,0 +1,42 @@
From patchwork Tue Mar 12 09:51:41 2019
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10848959
X-Patchwork-Delegate: kvalo@adurom.com
From: Stanislaw Gruszka <sgruszka@redhat.com>
To: linux-wireless@vger.kernel.org
Cc: =?utf-8?q?Tomislav_Po=C5=BEega?= <pozega.tomislav@gmail.com>,
Daniel Golle <daniel@makrotopia.org>, Felix Fietkau <nbd@nbd.name>,
Mathias Kresin <dev@kresin.me>
Subject: [PATCH v3 2/4] rt2x00: use ratelimited variants dev_warn/dev_err
Date: Tue, 12 Mar 2019 10:51:41 +0100
Message-Id: <1552384303-29529-3-git-send-email-sgruszka@redhat.com>
In-Reply-To: <1552384303-29529-1-git-send-email-sgruszka@redhat.com>
References: <1552384303-29529-1-git-send-email-sgruszka@redhat.com>
As reported by Randy we can overwhelm logs on some USB error conditions.
To avoid that use dev_warn_ratelimited() and dev_err_ratelimitd().
Reported-and-tested-by: Randy Oostdyk <linux-kernel@oostdyk.com>
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -69,10 +69,10 @@
printk(KERN_ERR KBUILD_MODNAME ": %s: Error - " fmt, \
__func__, ##__VA_ARGS__)
#define rt2x00_err(dev, fmt, ...) \
- wiphy_err((dev)->hw->wiphy, "%s: Error - " fmt, \
+ wiphy_err_ratelimited((dev)->hw->wiphy, "%s: Error - " fmt, \
__func__, ##__VA_ARGS__)
#define rt2x00_warn(dev, fmt, ...) \
- wiphy_warn((dev)->hw->wiphy, "%s: Warning - " fmt, \
+ wiphy_warn_ratelimited((dev)->hw->wiphy, "%s: Warning - " fmt, \
__func__, ##__VA_ARGS__)
#define rt2x00_info(dev, fmt, ...) \
wiphy_info((dev)->hw->wiphy, "%s: Info - " fmt, \

View File

@@ -0,0 +1,96 @@
From patchwork Tue Mar 12 09:51:42 2019
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10848961
X-Patchwork-Delegate: kvalo@adurom.com
From: Stanislaw Gruszka <sgruszka@redhat.com>
To: linux-wireless@vger.kernel.org
Cc: =?utf-8?q?Tomislav_Po=C5=BEega?= <pozega.tomislav@gmail.com>,
Daniel Golle <daniel@makrotopia.org>, Felix Fietkau <nbd@nbd.name>,
Mathias Kresin <dev@kresin.me>
Subject: [PATCH v3 3/4] rt2x00: check number of EPROTO errors
Date: Tue, 12 Mar 2019 10:51:42 +0100
Message-Id: <1552384303-29529-4-git-send-email-sgruszka@redhat.com>
In-Reply-To: <1552384303-29529-1-git-send-email-sgruszka@redhat.com>
References: <1552384303-29529-1-git-send-email-sgruszka@redhat.com>
Some USB host devices/drivers on some conditions can always return
EPROTO error on submitted URBs. That can cause infinity loop in the
rt2x00 driver.
Since we can have single EPROTO errors we can not mark as device as
removed to avoid infinity loop. However we can count consecutive
EPROTO errors and mark device as removed if get lot of it.
I choose number 10 as threshold.
Reported-and-tested-by: Randy Oostdyk <linux-kernel@oostdyk.com>
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 +
drivers/net/wireless/ralink/rt2x00/rt2x00usb.c | 22 +++++++++++++++++++---
2 files changed, 20 insertions(+), 3 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -1016,6 +1016,7 @@ struct rt2x00_dev {
unsigned int extra_tx_headroom;
struct usb_anchor *anchor;
+ unsigned int num_proto_errs;
/* Clock for System On Chip devices. */
struct clk *clk;
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
@@ -31,6 +31,22 @@
#include "rt2x00.h"
#include "rt2x00usb.h"
+static bool rt2x00usb_check_usb_error(struct rt2x00_dev *rt2x00dev, int status)
+{
+ if (status == -ENODEV || status == -ENOENT)
+ return true;
+
+ if (status == -EPROTO || status == -ETIMEDOUT)
+ rt2x00dev->num_proto_errs++;
+ else
+ rt2x00dev->num_proto_errs = 0;
+
+ if (rt2x00dev->num_proto_errs > 3)
+ return true;
+
+ return false;
+}
+
/*
* Interfacing with the HW.
*/
@@ -57,7 +73,7 @@ int rt2x00usb_vendor_request(struct rt2x
if (status >= 0)
return 0;
- if (status == -ENODEV || status == -ENOENT) {
+ if (rt2x00usb_check_usb_error(rt2x00dev, status)) {
/* Device has disappeared. */
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
break;
@@ -321,7 +337,7 @@ static bool rt2x00usb_kick_tx_entry(stru
status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
if (status) {
- if (status == -ENODEV || status == -ENOENT)
+ if (rt2x00usb_check_usb_error(rt2x00dev, status))
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
@@ -410,7 +426,7 @@ static bool rt2x00usb_kick_rx_entry(stru
status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
if (status) {
- if (status == -ENODEV || status == -ENOENT)
+ if (rt2x00usb_check_usb_error(rt2x00dev, status))
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);

View File

@@ -0,0 +1,43 @@
From patchwork Tue Mar 12 09:51:43 2019
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10848963
X-Patchwork-Delegate: kvalo@adurom.com
From: Stanislaw Gruszka <sgruszka@redhat.com>
To: linux-wireless@vger.kernel.org
Cc: =?utf-8?q?Tomislav_Po=C5=BEega?= <pozega.tomislav@gmail.com>,
Daniel Golle <daniel@makrotopia.org>, Felix Fietkau <nbd@nbd.name>,
Mathias Kresin <dev@kresin.me>
Subject: [PATCH v3 4/4] rt2x00: do not print error when queue is full
Date: Tue, 12 Mar 2019 10:51:43 +0100
Message-Id: <1552384303-29529-5-git-send-email-sgruszka@redhat.com>
In-Reply-To: <1552384303-29529-1-git-send-email-sgruszka@redhat.com>
References: <1552384303-29529-1-git-send-email-sgruszka@redhat.com>
For unknown reasons printk() on some context can cause CPU hung on
embedded MT7620 AP/router MIPS platforms. What can result on wifi
disconnects.
This patch move queue full messages to debug level what is consistent
with other mac80211 drivers which drop packet silently if tx queue is
full. This make MT7620 OpenWRT routers more stable, what was reported
by various users.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
@@ -674,7 +674,7 @@ int rt2x00queue_write_tx_frame(struct da
spin_lock(&queue->tx_lock);
if (unlikely(rt2x00queue_full(queue))) {
- rt2x00_err(queue->rt2x00dev, "Dropping frame due to full tx queue %d\n",
+ rt2x00_dbg(queue->rt2x00dev, "Dropping frame due to full tx queue %d\n",
queue->qid);
ret = -ENOBUFS;
goto out;

View File

@@ -0,0 +1,128 @@
From 91a5340db0526b7263bc8da14b120ea3129b5f28 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 9 Feb 2019 12:08:31 +0100
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10804437
X-Patchwork-Delegate: kvalo@adurom.com
Subject: [PATCH 21/28] rt2800: partially restore old mmio txstatus behaviour
Do not disable txstatus interrupt and add quota of processed tx statuses in
one tasklet. Quota is needed to allow to fed device with new frames during
processing of tx statuses.
Patch fixes about 15% performance degradation on some scenarios coused by
0b0d556e0ebb ("rt2800mmio: use txdone/txstatus routines from lib").
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 4 +--
.../net/wireless/ralink/rt2x00/rt2800lib.h | 2 +-
.../net/wireless/ralink/rt2x00/rt2800mmio.c | 30 +++++--------------
.../net/wireless/ralink/rt2x00/rt2800usb.c | 2 +-
4 files changed, 12 insertions(+), 26 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1100,7 +1100,7 @@ void rt2800_txdone_entry(struct queue_en
}
EXPORT_SYMBOL_GPL(rt2800_txdone_entry);
-void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
+void rt2800_txdone(struct rt2x00_dev *rt2x00dev, unsigned int quota)
{
struct data_queue *queue;
struct queue_entry *entry;
@@ -1108,7 +1108,7 @@ void rt2800_txdone(struct rt2x00_dev *rt
u8 qid;
bool match;
- while (kfifo_get(&rt2x00dev->txstatus_fifo, &reg)) {
+ while (quota-- > 0 && 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 .
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -195,7 +195,7 @@ 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(struct rt2x00_dev *rt2x00dev, unsigned int quota);
void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev);
bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev);
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
@@ -255,20 +255,6 @@ void rt2800mmio_autowake_tasklet(unsigne
}
EXPORT_SYMBOL_GPL(rt2800mmio_autowake_tasklet);
-static void rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev)
-{
- bool timeout = false;
-
- while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) ||
- (timeout = rt2800_txstatus_timeout(rt2x00dev))) {
-
- rt2800_txdone(rt2x00dev);
-
- if (timeout)
- rt2800_txdone_nostatus(rt2x00dev);
- }
-}
-
static bool rt2800mmio_fetch_txstatus(struct rt2x00_dev *rt2x00dev)
{
u32 status;
@@ -305,14 +291,11 @@ void rt2800mmio_txstatus_tasklet(unsigne
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
- do {
- rt2800mmio_txdone(rt2x00dev);
+ rt2800_txdone(rt2x00dev, 16);
- } while (rt2800mmio_fetch_txstatus(rt2x00dev));
+ if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo))
+ tasklet_schedule(&rt2x00dev->txstatus_tasklet);
- if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2800mmio_enable_interrupt(rt2x00dev,
- INT_SOURCE_CSR_TX_FIFO_STATUS);
}
EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
@@ -339,8 +322,10 @@ irqreturn_t rt2800mmio_interrupt(int irq
mask = ~reg;
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
+ rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1);
rt2800mmio_fetch_txstatus(rt2x00dev);
- tasklet_schedule(&rt2x00dev->txstatus_tasklet);
+ if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo))
+ tasklet_schedule(&rt2x00dev->txstatus_tasklet);
}
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
@@ -500,7 +485,8 @@ void rt2800mmio_flush_queue(struct data_
*/
if (tx_queue) {
tasklet_disable(&rt2x00dev->txstatus_tasklet);
- rt2800mmio_txdone(rt2x00dev);
+ rt2800_txdone(rt2x00dev, UINT_MAX);
+ rt2800_txdone_nostatus(rt2x00dev);
tasklet_enable(&rt2x00dev->txstatus_tasklet);
}
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -480,7 +480,7 @@ static void rt2800usb_work_txdone(struct
while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) ||
rt2800_txstatus_timeout(rt2x00dev)) {
- rt2800_txdone(rt2x00dev);
+ rt2800_txdone(rt2x00dev, UINT_MAX);
rt2800_txdone_nostatus(rt2x00dev);

View File

@@ -0,0 +1,27 @@
From 11f8ad1656035176bad9d89de7ea0e7fe6d82c32 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 9 Feb 2019 12:08:32 +0100
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10804439
X-Patchwork-Delegate: kvalo@adurom.com
Subject: [PATCH 22/28] rt2800: new flush implementation for SoC devices
Use new flush_queue() calback for SoC devices, what was already done for
PCIe devices.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2800soc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -203,7 +203,7 @@ static const struct rt2x00lib_ops rt2800
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
- .flush_queue = rt2x00mmio_flush_queue,
+ .flush_queue = rt2800mmio_flush_queue,
.write_tx_desc = rt2800mmio_write_tx_desc,
.write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,

View File

@@ -0,0 +1,106 @@
From 2bbea7645c3d095014a080db170941818650e141 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 9 Feb 2019 12:08:33 +0100
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10804441
X-Patchwork-Delegate: kvalo@adurom.com
Subject: [PATCH 23/28] rt2800: move txstatus pending routine
Move rt2800usb_txstatus_pending routine to rt2800lib. It will be reused
by rt2800mmio code.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 17 ++++++++++++++
.../net/wireless/ralink/rt2x00/rt2800lib.h | 1 +
.../net/wireless/ralink/rt2x00/rt2800usb.c | 22 +++----------------
3 files changed, 21 insertions(+), 19 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1183,6 +1183,23 @@ bool rt2800_txstatus_timeout(struct rt2x
}
EXPORT_SYMBOL_GPL(rt2800_txstatus_timeout);
+/*
+ * test if there is an entry in any TX queue for which DMA is done
+ * but the TX status has not been returned yet
+ */
+bool rt2800_txstatus_pending(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ tx_queue_for_each(rt2x00dev, queue) {
+ if (rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE) !=
+ rt2x00queue_get_entry(queue, Q_INDEX_DONE))
+ return true;
+ }
+ return false;
+}
+EXPORT_SYMBOL_GPL(rt2800_txstatus_pending);
+
void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -198,6 +198,7 @@ void rt2800_txdone_entry(struct queue_en
void rt2800_txdone(struct rt2x00_dev *rt2x00dev, unsigned int quota);
void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev);
bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev);
+bool rt2800_txstatus_pending(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
@@ -100,22 +100,6 @@ static void rt2800usb_stop_queue(struct
}
}
-/*
- * test if there is an entry in any TX queue for which DMA is done
- * but the TX status has not been returned yet
- */
-static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
-
- tx_queue_for_each(rt2x00dev, queue) {
- if (rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE) !=
- rt2x00queue_get_entry(queue, Q_INDEX_DONE))
- return true;
- }
- return false;
-}
-
#define TXSTATUS_READ_INTERVAL 1000000
static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
@@ -145,7 +129,7 @@ static bool rt2800usb_tx_sta_fifo_read_c
if (rt2800_txstatus_timeout(rt2x00dev))
queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
- if (rt2800usb_txstatus_pending(rt2x00dev)) {
+ if (rt2800_txstatus_pending(rt2x00dev)) {
/* Read register after 1 ms */
hrtimer_start(&rt2x00dev->txstatus_timer,
TXSTATUS_READ_INTERVAL,
@@ -160,7 +144,7 @@ stop_reading:
* clear_bit someone could do rt2x00usb_interrupt_txdone, so recheck
* here again if status reading is needed.
*/
- if (rt2800usb_txstatus_pending(rt2x00dev) &&
+ if (rt2800_txstatus_pending(rt2x00dev) &&
!test_and_set_bit(TX_STATUS_READING, &rt2x00dev->flags))
return true;
else
@@ -489,7 +473,7 @@ static void rt2800usb_work_txdone(struct
* if the medium is busy, thus the TX_STA_FIFO entry is
* also delayed -> use a timer to retrieve it.
*/
- if (rt2800usb_txstatus_pending(rt2x00dev))
+ if (rt2800_txstatus_pending(rt2x00dev))
rt2800usb_async_read_tx_status(rt2x00dev);
}
}

View File

@@ -0,0 +1,61 @@
From f6a9618198e190a2ba09ce3f0aa8e9ee1763bd38 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 9 Feb 2019 12:08:34 +0100
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10804443
X-Patchwork-Delegate: kvalo@adurom.com
Subject: [PATCH 24/28] rt2800mmio: fetch tx status changes
Prepare to use rt2800mmio_fetch_txstatus() in concurrent manner and drop
return value since is not longer needed.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2800mmio.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
@@ -255,12 +255,12 @@ void rt2800mmio_autowake_tasklet(unsigne
}
EXPORT_SYMBOL_GPL(rt2800mmio_autowake_tasklet);
-static bool rt2800mmio_fetch_txstatus(struct rt2x00_dev *rt2x00dev)
+static void rt2800mmio_fetch_txstatus(struct rt2x00_dev *rt2x00dev)
{
u32 status;
- bool more = false;
+ unsigned long flags;
- /* FIXEME: rewrite this comment
+ /*
* The TX_FIFO_STATUS interrupt needs special care. We should
* read TX_STA_FIFO but we should do it immediately as otherwise
* the register can overflow and we would lose status reports.
@@ -271,20 +271,21 @@ static bool rt2800mmio_fetch_txstatus(st
* because we can schedule the tasklet multiple times (when the
* interrupt fires again during tx status processing).
*
- * txstatus tasklet is called with INT_SOURCE_CSR_TX_FIFO_STATUS
- * disabled so have only one producer and one consumer - we don't
- * need to lock the kfifo.
+ * We also read statuses from tx status timeout timer, use
+ * lock to prevent concurent writes to fifo.
*/
+
+ spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
+
while (!kfifo_is_full(&rt2x00dev->txstatus_fifo)) {
status = rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO);
if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
break;
kfifo_put(&rt2x00dev->txstatus_fifo, status);
- more = true;
}
- return more;
+ spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
}
void rt2800mmio_txstatus_tasklet(unsigned long data)

View File

@@ -0,0 +1,194 @@
From 175c2548332b45b144af673e70fdbb1a947d7aba Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 9 Feb 2019 12:08:35 +0100
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10804445
X-Patchwork-Delegate: kvalo@adurom.com
Subject: [PATCH 25/28] rt2800mmio: use timer and work for handling tx statuses
timeouts
Sometimes we can get into situation when there are pending statuses,
but we do not get INT_SOURCE_CSR_TX_FIFO_STATUS. Handle this situation
by arming timeout timer and read statuses (it will fix case when
we just do not have irq) and queue work to handle case we missed
statues from hardware FIFO.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
.../net/wireless/ralink/rt2x00/rt2800mmio.c | 81 +++++++++++++++++--
.../net/wireless/ralink/rt2x00/rt2800mmio.h | 1 +
.../net/wireless/ralink/rt2x00/rt2800pci.c | 2 +-
.../net/wireless/ralink/rt2x00/rt2800soc.c | 2 +-
.../net/wireless/ralink/rt2x00/rt2x00dev.c | 4 +
5 files changed, 82 insertions(+), 8 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
@@ -426,6 +426,9 @@ void rt2800mmio_start_queue(struct data_
}
EXPORT_SYMBOL_GPL(rt2800mmio_start_queue);
+/* 200 ms */
+#define TXSTATUS_TIMEOUT 200000000
+
void rt2800mmio_kick_queue(struct data_queue *queue)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
@@ -440,6 +443,8 @@ void rt2800mmio_kick_queue(struct data_q
entry = rt2x00queue_get_entry(queue, Q_INDEX);
rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX(queue->qid),
entry->entry_idx);
+ hrtimer_start(&rt2x00dev->txstatus_timer,
+ TXSTATUS_TIMEOUT, HRTIMER_MODE_REL);
break;
case QID_MGMT:
entry = rt2x00queue_get_entry(queue, Q_INDEX);
@@ -484,12 +489,8 @@ void rt2800mmio_flush_queue(struct data_
* For TX queues schedule completion tasklet to catch
* tx status timeouts, othewise just wait.
*/
- if (tx_queue) {
- tasklet_disable(&rt2x00dev->txstatus_tasklet);
- rt2800_txdone(rt2x00dev, UINT_MAX);
- rt2800_txdone_nostatus(rt2x00dev);
- tasklet_enable(&rt2x00dev->txstatus_tasklet);
- }
+ if (tx_queue)
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
/*
* Wait for a little while to give the driver
@@ -627,6 +628,10 @@ void rt2800mmio_clear_entry(struct queue
word = rt2x00_desc_read(entry_priv->desc, 1);
rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1);
rt2x00_desc_write(entry_priv->desc, 1, word);
+
+ /* If last entry stop txstatus timer */
+ if (entry->queue->length == 1)
+ hrtimer_cancel(&rt2x00dev->txstatus_timer);
}
}
EXPORT_SYMBOL_GPL(rt2800mmio_clear_entry);
@@ -759,6 +764,70 @@ int rt2800mmio_enable_radio(struct rt2x0
}
EXPORT_SYMBOL_GPL(rt2800mmio_enable_radio);
+static void rt2800mmio_work_txdone(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, txdone_work);
+
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) ||
+ rt2800_txstatus_timeout(rt2x00dev)) {
+
+ tasklet_disable(&rt2x00dev->txstatus_tasklet);
+ rt2800_txdone(rt2x00dev, UINT_MAX);
+ rt2800_txdone_nostatus(rt2x00dev);
+ tasklet_enable(&rt2x00dev->txstatus_tasklet);
+ }
+
+ if (rt2800_txstatus_pending(rt2x00dev))
+ hrtimer_start(&rt2x00dev->txstatus_timer,
+ TXSTATUS_TIMEOUT, HRTIMER_MODE_REL);
+}
+
+static enum hrtimer_restart rt2800mmio_tx_sta_fifo_timeout(struct hrtimer *timer)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(timer, struct rt2x00_dev, txstatus_timer);
+
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ goto out;
+
+ if (!rt2800_txstatus_pending(rt2x00dev))
+ goto out;
+
+ rt2800mmio_fetch_txstatus(rt2x00dev);
+ if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo))
+ tasklet_schedule(&rt2x00dev->txstatus_tasklet);
+ else
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
+out:
+ return HRTIMER_NORESTART;
+}
+
+int rt2800mmio_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ retval = rt2800_probe_hw(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Set txstatus timer function.
+ */
+ rt2x00dev->txstatus_timer.function = rt2800mmio_tx_sta_fifo_timeout;
+
+ /*
+ * Overwrite TX done handler
+ */
+ INIT_WORK(&rt2x00dev->txdone_work, rt2800mmio_work_txdone);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2800mmio_probe_hw);
+
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("rt2800 MMIO library");
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
@@ -153,6 +153,7 @@ void rt2800mmio_stop_queue(struct data_q
void rt2800mmio_queue_init(struct data_queue *queue);
/* Initialization functions */
+int rt2800mmio_probe_hw(struct rt2x00_dev *rt2x00dev);
bool rt2800mmio_get_entry_state(struct queue_entry *entry);
void rt2800mmio_clear_entry(struct queue_entry *entry);
int rt2800mmio_init_queues(struct rt2x00_dev *rt2x00dev);
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -346,7 +346,7 @@ static const struct rt2x00lib_ops rt2800
.tbtt_tasklet = rt2800mmio_tbtt_tasklet,
.rxdone_tasklet = rt2800mmio_rxdone_tasklet,
.autowake_tasklet = rt2800mmio_autowake_tasklet,
- .probe_hw = rt2800_probe_hw,
+ .probe_hw = rt2800mmio_probe_hw,
.get_firmware_name = rt2800pci_get_firmware_name,
.check_firmware = rt2800_check_firmware,
.load_firmware = rt2800_load_firmware,
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -185,7 +185,7 @@ static const struct rt2x00lib_ops rt2800
.tbtt_tasklet = rt2800mmio_tbtt_tasklet,
.rxdone_tasklet = rt2800mmio_rxdone_tasklet,
.autowake_tasklet = rt2800mmio_autowake_tasklet,
- .probe_hw = rt2800_probe_hw,
+ .probe_hw = rt2800mmio_probe_hw,
.get_firmware_name = rt2800soc_get_firmware_name,
.check_firmware = rt2800soc_check_firmware,
.load_firmware = rt2800soc_load_firmware,
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1391,6 +1391,8 @@ int rt2x00lib_probe_dev(struct rt2x00_de
mutex_init(&rt2x00dev->conf_mutex);
INIT_LIST_HEAD(&rt2x00dev->bar_list);
spin_lock_init(&rt2x00dev->bar_list_lock);
+ hrtimer_init(&rt2x00dev->txstatus_timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
@@ -1515,6 +1517,8 @@ void rt2x00lib_remove_dev(struct rt2x00_
cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
cancel_work_sync(&rt2x00dev->sleep_work);
+ hrtimer_cancel(&rt2x00dev->txstatus_timer);
+
/*
* Kill the tx status tasklet.
*/

View File

@@ -0,0 +1,57 @@
From 6013a91f15c9dabd668d5736652b9bcfb0ef0378 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 9 Feb 2019 12:08:36 +0100
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10804447
X-Patchwork-Delegate: kvalo@adurom.com
Subject: [PATCH 26/28] rt2x00: remove last_nostatus_check
We do not any longer check txstatus timeout from tasklet, so do not need
this optimization.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 9 ---------
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 2 --
drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 1 -
3 files changed, 12 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1164,15 +1164,6 @@ bool rt2800_txstatus_timeout(struct rt2x
struct data_queue *queue;
struct queue_entry *entry;
- if (!test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags)) {
- unsigned long tout = msecs_to_jiffies(1000);
-
- if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout))
- return false;
- }
-
- rt2x00dev->last_nostatus_check = jiffies;
-
tx_queue_for_each(rt2x00dev, queue) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
if (rt2800_entry_txstatus_timeout(rt2x00dev, entry))
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -980,8 +980,6 @@ struct rt2x00_dev {
*/
DECLARE_KFIFO_PTR(txstatus_fifo, u32);
- unsigned long last_nostatus_check;
-
/*
* Timer to ensure tx status reports are read (rt2800usb).
*/
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
@@ -1042,7 +1042,6 @@ void rt2x00queue_start_queues(struct rt2
*/
tx_queue_for_each(rt2x00dev, queue)
rt2x00queue_start_queue(queue);
- rt2x00dev->last_nostatus_check = jiffies;
rt2x00queue_start_queue(rt2x00dev->rx);
}

View File

@@ -0,0 +1,34 @@
From 2758f09b22bc08e89e0391486b2d707ad2479599 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 9 Feb 2019 12:08:37 +0100
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10804449
X-Patchwork-Delegate: kvalo@adurom.com
Subject: [PATCH 27/28] rt2x00: remove not used entry field
Remove not used any longer queue_entry field and flag.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2x00queue.h | 3 ---
1 file changed, 3 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h
@@ -361,7 +361,6 @@ enum queue_entry_flags {
ENTRY_DATA_PENDING,
ENTRY_DATA_IO_FAILED,
ENTRY_DATA_STATUS_PENDING,
- ENTRY_DATA_STATUS_SET,
};
/**
@@ -387,8 +386,6 @@ struct queue_entry {
unsigned int entry_idx;
- u32 status;
-
void *priv_data;
};

View File

@@ -0,0 +1,26 @@
From f44e145869bb517460648e4ed71b7e9001964d06 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 9 Feb 2019 12:08:38 +0100
X-Patchwork-Submitter: Stanislaw Gruszka <sgruszka@redhat.com>
X-Patchwork-Id: 10804451
X-Patchwork-Delegate: kvalo@adurom.com
Subject: [PATCH 28/28] rt2x00mmio: remove legacy comment
Remove comment about fields that ware removed.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h | 2 --
1 file changed, 2 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h
@@ -80,8 +80,6 @@ int rt2x00mmio_regbusy_read(struct rt2x0
*
* @desc: Pointer to device descriptor
* @desc_dma: DMA pointer to &desc.
- * @data: Pointer to device's entry memory.
- * @data_dma: DMA pointer to &data.
*/
struct queue_entry_priv_mmio {
__le32 *desc;

View File

@@ -0,0 +1,959 @@
From d0e61a0f7cca51ce340a5a73595189972122ff25 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Wed, 24 Apr 2019 09:49:24 +0200
Subject: [PATCH] rt2x00: add RT3883 support
Patch add support for RT3883 chip. Code was taken direclty
from openwrt project and merge into one patch.
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800.h | 19 +-
.../net/wireless/ralink/rt2x00/rt2800lib.c | 598 +++++++++++++++++-
.../net/wireless/ralink/rt2x00/rt2800soc.c | 9 +-
3 files changed, 607 insertions(+), 19 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
@@ -48,7 +48,8 @@
* RF2853 2.4G/5G 3T3R
* RF3320 2.4G 1T1R(RT3350/RT3370/RT3390)
* RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
- * RF3053 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
+ * RF3053 2.4G/5G 3T3R(RT3563/RT3573/RT3593)
+ * RF3853 2.4G/5G 3T3R(RT3883/RT3662)
* RF5592 2.4G/5G 2T2R
* RF3070 2.4G 1T1R
* RF5360 2.4G 1T1R
@@ -72,6 +73,7 @@
#define RF5592 0x000f
#define RF3070 0x3070
#define RF3290 0x3290
+#define RF3853 0x3853
#define RF5350 0x5350
#define RF5360 0x5360
#define RF5362 0x5362
@@ -1726,6 +1728,20 @@
#define TX_PWR_CFG_9B_STBC_MCS7 FIELD32(0x000000ff)
/*
+ * TX_TXBF_CFG:
+ */
+#define TX_TXBF_CFG_0 0x138c
+#define TX_TXBF_CFG_1 0x13a4
+#define TX_TXBF_CFG_2 0x13a8
+#define TX_TXBF_CFG_3 0x13ac
+
+/*
+ * TX_FBK_CFG_3S:
+ */
+#define TX_FBK_CFG_3S_0 0x13c4
+#define TX_FBK_CFG_3S_1 0x13c8
+
+/*
* RX_FILTER_CFG: RX configuration register.
*/
#define RX_FILTER_CFG 0x1400
@@ -2296,6 +2312,7 @@ struct mac_iveiv_entry {
/*
* RFCSR 2:
*/
+#define RFCSR2_RESCAL_BP FIELD8(0x40)
#define RFCSR2_RESCAL_EN FIELD8(0x80)
#define RFCSR2_RX2_EN_MT7620 FIELD8(0x02)
#define RFCSR2_TX2_EN_MT7620 FIELD8(0x20)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -381,7 +381,8 @@ static unsigned int rt2800_eeprom_word_i
wiphy_name(rt2x00dev->hw->wiphy), word))
return 0;
- if (rt2x00_rt(rt2x00dev, RT3593))
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883))
map = rt2800_eeprom_map_ext;
else
map = rt2800_eeprom_map;
@@ -590,6 +591,7 @@ void rt2800_get_txwi_rxwi_size(struct rt
{
switch (rt2x00dev->chip.rt) {
case RT3593:
+ case RT3883:
*txwi_size = TXWI_DESC_SIZE_4WORDS;
*rxwi_size = RXWI_DESC_SIZE_5WORDS;
break;
@@ -2180,7 +2182,8 @@ void rt2800_config_ant(struct rt2x00_dev
rt2800_bbp_write(rt2x00dev, 3, r3);
rt2800_bbp_write(rt2x00dev, 1, r1);
- if (rt2x00_rt(rt2x00dev, RT3593)) {
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883)) {
if (ant->rx_chain_num == 1)
rt2800_bbp_write(rt2x00dev, 86, 0x00);
else
@@ -2202,7 +2205,8 @@ static void rt2800_config_lna_gain(struc
eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_LNA);
lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0);
} else if (libconf->rf.channel <= 128) {
- if (rt2x00_rt(rt2x00dev, RT3593)) {
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883)) {
eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2);
lna_gain = rt2x00_get_field16(eeprom,
EEPROM_EXT_LNA2_A1);
@@ -2212,7 +2216,8 @@ static void rt2800_config_lna_gain(struc
EEPROM_RSSI_BG2_LNA_A1);
}
} else {
- if (rt2x00_rt(rt2x00dev, RT3593)) {
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883)) {
eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2);
lna_gain = rt2x00_get_field16(eeprom,
EEPROM_EXT_LNA2_A2);
@@ -2880,6 +2885,211 @@ static void rt2800_config_channel_rf3053
}
}
+static void rt2800_config_channel_rf3853(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf,
+ struct rf_channel *rf,
+ struct channel_info *info)
+{
+ u8 rfcsr;
+ u8 bbp;
+ u8 pwr1, pwr2, pwr3;
+
+ const bool txbf_enabled = false; /* TODO */
+
+ /* TODO: add band selection */
+
+ if (rf->channel <= 14)
+ rt2800_rfcsr_write(rt2x00dev, 6, 0x40);
+ else if (rf->channel < 132)
+ rt2800_rfcsr_write(rt2x00dev, 6, 0x80);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 6, 0x40);
+
+ rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
+ rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3);
+
+ if (rf->channel <= 14)
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x46);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x48);
+
+ if (rf->channel <= 14)
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x1a);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x52);
+
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x12);
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 1);
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
+ rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1);
+
+ switch (rt2x00dev->default_ant.tx_chain_num) {
+ case 3:
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1);
+ /* fallthrough */
+ case 2:
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
+ /* fallthrough */
+ case 1:
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1);
+ break;
+ }
+
+ switch (rt2x00dev->default_ant.rx_chain_num) {
+ case 3:
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1);
+ /* fallthrough */
+ case 2:
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
+ /* fallthrough */
+ case 1:
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
+ break;
+ }
+ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
+
+ rt2800_freq_cal_mode1(rt2x00dev);
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 30);
+ if (!conf_is_ht40(conf))
+ rfcsr &= ~(0x06);
+ else
+ rfcsr |= 0x06;
+ rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
+
+ if (rf->channel <= 14)
+ rt2800_rfcsr_write(rt2x00dev, 31, 0xa0);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+
+ if (conf_is_ht40(conf))
+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 32, 0xd8);
+
+ if (rf->channel <= 14)
+ rt2800_rfcsr_write(rt2x00dev, 34, 0x3c);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 34, 0x20);
+
+ /* loopback RF_BS */
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 36);
+ if (rf->channel <= 14)
+ rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 1);
+ else
+ rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 0);
+ rt2800_rfcsr_write(rt2x00dev, 36, rfcsr);
+
+ if (rf->channel <= 14)
+ rfcsr = 0x23;
+ else if (rf->channel < 100)
+ rfcsr = 0x36;
+ else if (rf->channel < 132)
+ rfcsr = 0x32;
+ else
+ rfcsr = 0x30;
+
+ if (txbf_enabled)
+ rfcsr |= 0x40;
+
+ rt2800_rfcsr_write(rt2x00dev, 39, rfcsr);
+
+ if (rf->channel <= 14)
+ rt2800_rfcsr_write(rt2x00dev, 44, 0x93);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 44, 0x9b);
+
+ if (rf->channel <= 14)
+ rfcsr = 0xbb;
+ else if (rf->channel < 100)
+ rfcsr = 0xeb;
+ else if (rf->channel < 132)
+ rfcsr = 0xb3;
+ else
+ rfcsr = 0x9b;
+ rt2800_rfcsr_write(rt2x00dev, 45, rfcsr);
+
+ if (rf->channel <= 14)
+ rfcsr = 0x8e;
+ else
+ rfcsr = 0x8a;
+
+ if (txbf_enabled)
+ rfcsr |= 0x20;
+
+ rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
+
+ rt2800_rfcsr_write(rt2x00dev, 50, 0x86);
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 51);
+ if (rf->channel <= 14)
+ rt2800_rfcsr_write(rt2x00dev, 51, 0x75);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 51, 0x51);
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 52);
+ if (rf->channel <= 14)
+ rt2800_rfcsr_write(rt2x00dev, 52, 0x45);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 52, 0x05);
+
+ if (rf->channel <= 14) {
+ pwr1 = info->default_power1 & 0x1f;
+ pwr2 = info->default_power2 & 0x1f;
+ pwr3 = info->default_power3 & 0x1f;
+ } else {
+ pwr1 = 0x48 | ((info->default_power1 & 0x18) << 1) |
+ (info->default_power1 & 0x7);
+ pwr2 = 0x48 | ((info->default_power2 & 0x18) << 1) |
+ (info->default_power2 & 0x7);
+ pwr3 = 0x48 | ((info->default_power3 & 0x18) << 1) |
+ (info->default_power3 & 0x7);
+ }
+
+ rt2800_rfcsr_write(rt2x00dev, 53, pwr1);
+ rt2800_rfcsr_write(rt2x00dev, 54, pwr2);
+ rt2800_rfcsr_write(rt2x00dev, 55, pwr3);
+
+ rt2x00_dbg(rt2x00dev, "Channel:%d, pwr1:%02x, pwr2:%02x, pwr3:%02x\n",
+ rf->channel, pwr1, pwr2, pwr3);
+
+ bbp = (info->default_power1 >> 5) |
+ ((info->default_power2 & 0xe0) >> 1);
+ rt2800_bbp_write(rt2x00dev, 109, bbp);
+
+ bbp = rt2800_bbp_read(rt2x00dev, 110);
+ bbp &= 0x0f;
+ bbp |= (info->default_power3 & 0xe0) >> 1;
+ rt2800_bbp_write(rt2x00dev, 110, bbp);
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 57);
+ if (rf->channel <= 14)
+ rt2800_rfcsr_write(rt2x00dev, 57, 0x6e);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 57, 0x3e);
+
+ /* Enable RF tuning */
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 3);
+ rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1);
+ rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
+
+ udelay(2000);
+
+ bbp = rt2800_bbp_read(rt2x00dev, 49);
+ /* clear update flag */
+ rt2800_bbp_write(rt2x00dev, 49, bbp & 0xfe);
+ rt2800_bbp_write(rt2x00dev, 49, bbp);
+
+ /* TODO: add calibration for TxBF */
+}
+
#define POWER_BOUND 0x27
#define POWER_BOUND_5G 0x2b
@@ -3683,19 +3893,51 @@ static char rt2800_txpower_to_dev(struct
unsigned int channel,
char txpower)
{
- if (rt2x00_rt(rt2x00dev, RT3593))
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883))
txpower = rt2x00_get_field8(txpower, EEPROM_TXPOWER_ALC);
if (channel <= 14)
return clamp_t(char, txpower, MIN_G_TXPOWER, MAX_G_TXPOWER);
- if (rt2x00_rt(rt2x00dev, RT3593))
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883))
return clamp_t(char, txpower, MIN_A_TXPOWER_3593,
MAX_A_TXPOWER_3593);
else
return clamp_t(char, txpower, MIN_A_TXPOWER, MAX_A_TXPOWER);
}
+static void rt3883_bbp_adjust(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf)
+{
+ u8 bbp;
+
+ bbp = (rf->channel > 14) ? 0x48 : 0x38;
+ rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, bbp);
+
+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
+
+ if (rf->channel <= 14) {
+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
+ } else {
+ /* Disable CCK packet detection */
+ rt2800_bbp_write(rt2x00dev, 70, 0x00);
+ }
+
+ rt2800_bbp_write(rt2x00dev, 73, 0x10);
+
+ if (rf->channel > 14) {
+ rt2800_bbp_write(rt2x00dev, 62, 0x1d);
+ rt2800_bbp_write(rt2x00dev, 63, 0x1d);
+ rt2800_bbp_write(rt2x00dev, 64, 0x1d);
+ } else {
+ rt2800_bbp_write(rt2x00dev, 62, 0x2d);
+ rt2800_bbp_write(rt2x00dev, 63, 0x2d);
+ rt2800_bbp_write(rt2x00dev, 64, 0x2d);
+ }
+}
+
static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf,
struct rf_channel *rf,
@@ -3714,6 +3956,12 @@ static void rt2800_config_channel(struct
rt2800_txpower_to_dev(rt2x00dev, rf->channel,
info->default_power3);
+ switch (rt2x00dev->chip.rt) {
+ case RT3883:
+ rt3883_bbp_adjust(rt2x00dev, rf);
+ break;
+ }
+
switch (rt2x00dev->chip.rf) {
case RF2020:
case RF3020:
@@ -3734,6 +3982,9 @@ static void rt2800_config_channel(struct
case RF3322:
rt2800_config_channel_rf3322(rt2x00dev, conf, rf, info);
break;
+ case RF3853:
+ rt2800_config_channel_rf3853(rt2x00dev, conf, rf, info);
+ break;
case RF3070:
case RF5350:
case RF5360:
@@ -3815,6 +4066,15 @@ static void rt2800_config_channel(struct
rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
rt2800_bbp_write(rt2x00dev, 77, 0x98);
+ } else if (rt2x00_rt(rt2x00dev, RT3883)) {
+ rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
+ rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
+ rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
+
+ if (rt2x00dev->default_ant.rx_chain_num > 1)
+ rt2800_bbp_write(rt2x00dev, 86, 0x46);
+ else
+ rt2800_bbp_write(rt2x00dev, 86, 0);
} else {
rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
@@ -3828,6 +4088,7 @@ static void rt2800_config_channel(struct
!rt2x00_rt(rt2x00dev, RT6352)) {
if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
rt2800_bbp_write(rt2x00dev, 82, 0x62);
+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
rt2800_bbp_write(rt2x00dev, 75, 0x46);
} else {
if (rt2x00_rt(rt2x00dev, RT3593))
@@ -3836,19 +4097,22 @@ static void rt2800_config_channel(struct
rt2800_bbp_write(rt2x00dev, 82, 0x84);
rt2800_bbp_write(rt2x00dev, 75, 0x50);
}
- if (rt2x00_rt(rt2x00dev, RT3593))
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883))
rt2800_bbp_write(rt2x00dev, 83, 0x8a);
}
} else {
if (rt2x00_rt(rt2x00dev, RT3572))
rt2800_bbp_write(rt2x00dev, 82, 0x94);
- else if (rt2x00_rt(rt2x00dev, RT3593))
+ else if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883))
rt2800_bbp_write(rt2x00dev, 82, 0x82);
else if (!rt2x00_rt(rt2x00dev, RT6352))
rt2800_bbp_write(rt2x00dev, 82, 0xf2);
- if (rt2x00_rt(rt2x00dev, RT3593))
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883))
rt2800_bbp_write(rt2x00dev, 83, 0x9a);
if (rt2x00_has_cap_external_lna_a(rt2x00dev))
@@ -3984,6 +4248,23 @@ static void rt2800_config_channel(struct
usleep_range(1000, 1500);
}
+ if (rt2x00_rt(rt2x00dev, RT3883)) {
+ if (!conf_is_ht40(conf))
+ rt2800_bbp_write(rt2x00dev, 105, 0x34);
+ else
+ rt2800_bbp_write(rt2x00dev, 105, 0x04);
+
+ /* AGC init */
+ if (rf->channel <= 14)
+ reg = 0x2e + rt2x00dev->lna_gain;
+ else
+ reg = 0x20 + ((rt2x00dev->lna_gain * 5) / 3);
+
+ rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg);
+
+ usleep_range(1000, 1500);
+ }
+
if (rt2x00_rt(rt2x00dev, RT5592) || rt2x00_rt(rt2x00dev, RT6352)) {
reg = 0x10;
if (!conf_is_ht40(conf)) {
@@ -4243,6 +4524,9 @@ static u8 rt2800_compensate_txpower(stru
if (rt2x00_rt(rt2x00dev, RT3593))
return min_t(u8, txpower, 0xc);
+ if (rt2x00_rt(rt2x00dev, RT3883))
+ return min_t(u8, txpower, 0xf);
+
if (rt2x00_has_cap_power_limit(rt2x00dev)) {
/*
* Check if eirp txpower exceed txpower_limit.
@@ -5004,7 +5288,8 @@ static void rt2800_config_txpower(struct
struct ieee80211_channel *chan,
int power_level)
{
- if (rt2x00_rt(rt2x00dev, RT3593))
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883))
rt2800_config_txpower_rt3593(rt2x00dev, chan, power_level);
else if (rt2x00_rt(rt2x00dev, RT6352))
rt2800_config_txpower_rt6352(rt2x00dev, chan, power_level);
@@ -5051,6 +5336,7 @@ void rt2800_vco_calibration(struct rt2x0
case RF3053:
case RF3070:
case RF3290:
+ case RF3853:
case RF5350:
case RF5360:
case RF5362:
@@ -5251,7 +5537,8 @@ static u8 rt2800_get_default_vgc(struct
else
vgc = 0x2e + rt2x00dev->lna_gain;
} else { /* 5GHZ band */
- if (rt2x00_rt(rt2x00dev, RT3593))
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883))
vgc = 0x20 + (rt2x00dev->lna_gain * 5) / 3;
else if (rt2x00_rt(rt2x00dev, RT5592))
vgc = 0x24 + (2 * rt2x00dev->lna_gain);
@@ -5271,7 +5558,8 @@ static inline void rt2800_set_vgc(struct
{
if (qual->vgc_level != vgc_level) {
if (rt2x00_rt(rt2x00dev, RT3572) ||
- rt2x00_rt(rt2x00dev, RT3593)) {
+ rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883)) {
rt2800_bbp_write_with_rx_chain(rt2x00dev, 66,
vgc_level);
} else if (rt2x00_rt(rt2x00dev, RT5592)) {
@@ -5318,6 +5606,11 @@ void rt2800_link_tuner(struct rt2x00_dev
}
break;
+ case RT3883:
+ if (qual->rssi > -65)
+ vgc += 0x10;
+ break;
+
case RT5592:
if (qual->rssi > -65)
vgc += 0x20;
@@ -5470,6 +5763,12 @@ static int rt2800_init_registers(struct
rt2800_register_write(rt2x00dev, TX_SW_CFG2,
0x00000000);
}
+ } else if (rt2x00_rt(rt2x00dev, RT3883)) {
+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000402);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00040000);
+ rt2800_register_write(rt2x00dev, TX_TXBF_CFG_0, 0x8000fc21);
+ rt2800_register_write(rt2x00dev, TX_TXBF_CFG_3, 0x00009c40);
} else if (rt2x00_rt(rt2x00dev, RT5390) ||
rt2x00_rt(rt2x00dev, RT5392) ||
rt2x00_rt(rt2x00dev, RT6352)) {
@@ -5683,6 +5982,11 @@ static int rt2800_init_registers(struct
reg = rt2x00_rt(rt2x00dev, RT5592) ? 0x00000082 : 0x00000002;
rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, reg);
+ if (rt2x00_rt(rt2x00dev, RT3883)) {
+ rt2800_register_write(rt2x00dev, TX_FBK_CFG_3S_0, 0x12111008);
+ rt2800_register_write(rt2x00dev, TX_FBK_CFG_3S_1, 0x16151413);
+ }
+
reg = rt2800_register_read(rt2x00dev, TX_RTS_CFG);
rt2x00_set_field32(&reg, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 7);
rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_THRES,
@@ -6299,6 +6603,47 @@ static void rt2800_init_bbp_3593(struct
rt2800_bbp_write(rt2x00dev, 103, 0xc0);
}
+static void rt2800_init_bbp_3883(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_init_bbp_early(rt2x00dev);
+
+ rt2800_bbp_write(rt2x00dev, 4, 0x50);
+ rt2800_bbp_write(rt2x00dev, 47, 0x48);
+
+ rt2800_bbp_write(rt2x00dev, 86, 0x46);
+ rt2800_bbp_write(rt2x00dev, 88, 0x90);
+
+ rt2800_bbp_write(rt2x00dev, 92, 0x02);
+
+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
+ rt2800_bbp_write(rt2x00dev, 104, 0x92);
+ rt2800_bbp_write(rt2x00dev, 105, 0x34);
+ rt2800_bbp_write(rt2x00dev, 106, 0x12);
+ rt2800_bbp_write(rt2x00dev, 120, 0x50);
+ rt2800_bbp_write(rt2x00dev, 137, 0x0f);
+ rt2800_bbp_write(rt2x00dev, 163, 0x9d);
+
+ /* Set ITxBF timeout to 0x9C40=1000msec */
+ rt2800_bbp_write(rt2x00dev, 179, 0x02);
+ rt2800_bbp_write(rt2x00dev, 180, 0x00);
+ rt2800_bbp_write(rt2x00dev, 182, 0x40);
+ rt2800_bbp_write(rt2x00dev, 180, 0x01);
+ rt2800_bbp_write(rt2x00dev, 182, 0x9c);
+
+ rt2800_bbp_write(rt2x00dev, 179, 0x00);
+
+ /* Reprogram the inband interface to put right values in RXWI */
+ rt2800_bbp_write(rt2x00dev, 142, 0x04);
+ rt2800_bbp_write(rt2x00dev, 143, 0x3b);
+ rt2800_bbp_write(rt2x00dev, 142, 0x06);
+ rt2800_bbp_write(rt2x00dev, 143, 0xa0);
+ rt2800_bbp_write(rt2x00dev, 142, 0x07);
+ rt2800_bbp_write(rt2x00dev, 143, 0xa1);
+ rt2800_bbp_write(rt2x00dev, 142, 0x08);
+ rt2800_bbp_write(rt2x00dev, 143, 0xa2);
+ rt2800_bbp_write(rt2x00dev, 148, 0xc8);
+}
+
static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
{
int ant, div_mode;
@@ -6743,6 +7088,9 @@ static void rt2800_init_bbp(struct rt2x0
case RT3593:
rt2800_init_bbp_3593(rt2x00dev);
return;
+ case RT3883:
+ rt2800_init_bbp_3883(rt2x00dev);
+ return;
case RT5390:
case RT5392:
rt2800_init_bbp_53xx(rt2x00dev);
@@ -7614,6 +7962,144 @@ static void rt2800_init_rfcsr_5350(struc
rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
}
+static void rt2800_init_rfcsr_3883(struct rt2x00_dev *rt2x00dev)
+{
+ u8 rfcsr;
+
+ /* TODO: get the actual ECO value from the SoC */
+ const unsigned int eco = 5;
+
+ rt2800_rf_init_calibration(rt2x00dev, 2);
+
+ rt2800_rfcsr_write(rt2x00dev, 0, 0xe0);
+ rt2800_rfcsr_write(rt2x00dev, 1, 0x03);
+ rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
+ rt2800_rfcsr_write(rt2x00dev, 3, 0x20);
+ rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 5, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 6, 0x40);
+ rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 8, 0x5b);
+ rt2800_rfcsr_write(rt2x00dev, 9, 0x08);
+ rt2800_rfcsr_write(rt2x00dev, 10, 0xd3);
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x48);
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x1a);
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x12);
+ rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
+
+ /* RFCSR 17 will be initialized later based on the
+ * frequency offset stored in the EEPROM
+ */
+
+ rt2800_rfcsr_write(rt2x00dev, 18, 0x40);
+ rt2800_rfcsr_write(rt2x00dev, 19, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+ rt2800_rfcsr_write(rt2x00dev, 23, 0xc0);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 25, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 34, 0x20);
+ rt2800_rfcsr_write(rt2x00dev, 35, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 37, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 38, 0x86);
+ rt2800_rfcsr_write(rt2x00dev, 39, 0x23);
+ rt2800_rfcsr_write(rt2x00dev, 40, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 41, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 42, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 43, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 44, 0x93);
+ rt2800_rfcsr_write(rt2x00dev, 45, 0xbb);
+ rt2800_rfcsr_write(rt2x00dev, 46, 0x60);
+ rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 48, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 49, 0x8e);
+ rt2800_rfcsr_write(rt2x00dev, 50, 0x86);
+ rt2800_rfcsr_write(rt2x00dev, 51, 0x51);
+ rt2800_rfcsr_write(rt2x00dev, 52, 0x05);
+ rt2800_rfcsr_write(rt2x00dev, 53, 0x76);
+ rt2800_rfcsr_write(rt2x00dev, 54, 0x76);
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x76);
+ rt2800_rfcsr_write(rt2x00dev, 56, 0xdb);
+ rt2800_rfcsr_write(rt2x00dev, 57, 0x3e);
+ rt2800_rfcsr_write(rt2x00dev, 58, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+
+ /* TODO: rx filter calibration? */
+
+ rt2800_bbp_write(rt2x00dev, 137, 0x0f);
+
+ rt2800_bbp_write(rt2x00dev, 163, 0x9d);
+
+ rt2800_bbp_write(rt2x00dev, 105, 0x05);
+
+ rt2800_bbp_write(rt2x00dev, 179, 0x02);
+ rt2800_bbp_write(rt2x00dev, 180, 0x00);
+ rt2800_bbp_write(rt2x00dev, 182, 0x40);
+ rt2800_bbp_write(rt2x00dev, 180, 0x01);
+ rt2800_bbp_write(rt2x00dev, 182, 0x9c);
+
+ rt2800_bbp_write(rt2x00dev, 179, 0x00);
+
+ rt2800_bbp_write(rt2x00dev, 142, 0x04);
+ rt2800_bbp_write(rt2x00dev, 143, 0x3b);
+ rt2800_bbp_write(rt2x00dev, 142, 0x06);
+ rt2800_bbp_write(rt2x00dev, 143, 0xa0);
+ rt2800_bbp_write(rt2x00dev, 142, 0x07);
+ rt2800_bbp_write(rt2x00dev, 143, 0xa1);
+ rt2800_bbp_write(rt2x00dev, 142, 0x08);
+ rt2800_bbp_write(rt2x00dev, 143, 0xa2);
+ rt2800_bbp_write(rt2x00dev, 148, 0xc8);
+
+ if (eco == 5) {
+ rt2800_rfcsr_write(rt2x00dev, 32, 0xd8);
+ rt2800_rfcsr_write(rt2x00dev, 33, 0x32);
+ }
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 2);
+ rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_BP, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1);
+ rt2800_rfcsr_write(rt2x00dev, 2, rfcsr);
+ msleep(1);
+ rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 0);
+ rt2800_rfcsr_write(rt2x00dev, 2, rfcsr);
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 1);
+ rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
+ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 6);
+ rfcsr |= 0xc0;
+ rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 22);
+ rfcsr |= 0x20;
+ rt2800_rfcsr_write(rt2x00dev, 22, rfcsr);
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 46);
+ rfcsr |= 0x20;
+ rt2800_rfcsr_write(rt2x00dev, 46, rfcsr);
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 20);
+ rfcsr &= ~0xee;
+ rt2800_rfcsr_write(rt2x00dev, 20, rfcsr);
+}
+
static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
{
rt2800_rf_init_calibration(rt2x00dev, 2);
@@ -8456,6 +8942,9 @@ static void rt2800_init_rfcsr(struct rt2
case RT3390:
rt2800_init_rfcsr_3390(rt2x00dev);
break;
+ case RT3883:
+ rt2800_init_rfcsr_3883(rt2x00dev);
+ break;
case RT3572:
rt2800_init_rfcsr_3572(rt2x00dev);
break;
@@ -8661,7 +9150,8 @@ static u8 rt2800_get_txmixer_gain_24g(st
{
u16 word;
- if (rt2x00_rt(rt2x00dev, RT3593))
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883))
return 0;
word = rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG);
@@ -8675,7 +9165,8 @@ static u8 rt2800_get_txmixer_gain_5g(str
{
u16 word;
- if (rt2x00_rt(rt2x00dev, RT3593))
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883))
return 0;
word = rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A);
@@ -8781,7 +9272,8 @@ static int rt2800_validate_eeprom(struct
word = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0);
- if (!rt2x00_rt(rt2x00dev, RT3593)) {
+ if (!rt2x00_rt(rt2x00dev, RT3593) &&
+ !rt2x00_rt(rt2x00dev, RT3883)) {
if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 ||
rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff)
rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1,
@@ -8801,7 +9293,8 @@ static int rt2800_validate_eeprom(struct
word = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0);
- if (!rt2x00_rt(rt2x00dev, RT3593)) {
+ if (!rt2x00_rt(rt2x00dev, RT3593) &&
+ !rt2x00_rt(rt2x00dev, RT3883)) {
if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 ||
rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff)
rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2,
@@ -8809,7 +9302,8 @@ static int rt2800_validate_eeprom(struct
}
rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
- if (rt2x00_rt(rt2x00dev, RT3593)) {
+ if (rt2x00_rt(rt2x00dev, RT3593) ||
+ rt2x00_rt(rt2x00dev, RT3883)) {
word = rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2);
if (rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0x00 ||
rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0xff)
@@ -8848,6 +9342,8 @@ static int rt2800_init_eeprom(struct rt2
rf = rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID);
else if (rt2x00_rt(rt2x00dev, RT3352))
rf = RF3322;
+ else if (rt2x00_rt(rt2x00dev, RT3883))
+ rf = RF3853;
else if (rt2x00_rt(rt2x00dev, RT5350))
rf = RF5350;
else
@@ -8868,6 +9364,7 @@ static int rt2800_init_eeprom(struct rt2
case RF3290:
case RF3320:
case RF3322:
+ case RF3853:
case RF5350:
case RF5360:
case RF5362:
@@ -9154,6 +9651,66 @@ static const struct rf_channel rf_vals_3
{14, 0xF0, 2, 0x18},
};
+static const struct rf_channel rf_vals_3853[] = {
+ {1, 241, 6, 2},
+ {2, 241, 6, 7},
+ {3, 242, 6, 2},
+ {4, 242, 6, 7},
+ {5, 243, 6, 2},
+ {6, 243, 6, 7},
+ {7, 244, 6, 2},
+ {8, 244, 6, 7},
+ {9, 245, 6, 2},
+ {10, 245, 6, 7},
+ {11, 246, 6, 2},
+ {12, 246, 6, 7},
+ {13, 247, 6, 2},
+ {14, 248, 6, 4},
+
+ {36, 0x56, 8, 4},
+ {38, 0x56, 8, 6},
+ {40, 0x56, 8, 8},
+ {44, 0x57, 8, 0},
+ {46, 0x57, 8, 2},
+ {48, 0x57, 8, 4},
+ {52, 0x57, 8, 8},
+ {54, 0x57, 8, 10},
+ {56, 0x58, 8, 0},
+ {60, 0x58, 8, 4},
+ {62, 0x58, 8, 6},
+ {64, 0x58, 8, 8},
+
+ {100, 0x5b, 8, 8},
+ {102, 0x5b, 8, 10},
+ {104, 0x5c, 8, 0},
+ {108, 0x5c, 8, 4},
+ {110, 0x5c, 8, 6},
+ {112, 0x5c, 8, 8},
+ {114, 0x5c, 8, 10},
+ {116, 0x5d, 8, 0},
+ {118, 0x5d, 8, 2},
+ {120, 0x5d, 8, 4},
+ {124, 0x5d, 8, 8},
+ {126, 0x5d, 8, 10},
+ {128, 0x5e, 8, 0},
+ {132, 0x5e, 8, 4},
+ {134, 0x5e, 8, 6},
+ {136, 0x5e, 8, 8},
+ {140, 0x5f, 8, 0},
+
+ {149, 0x5f, 8, 9},
+ {151, 0x5f, 8, 11},
+ {153, 0x60, 8, 1},
+ {157, 0x60, 8, 5},
+ {159, 0x60, 8, 7},
+ {161, 0x60, 8, 9},
+ {165, 0x61, 8, 1},
+ {167, 0x61, 8, 3},
+ {169, 0x61, 8, 5},
+ {171, 0x61, 8, 7},
+ {173, 0x61, 8, 9},
+};
+
static const struct rf_channel rf_vals_5592_xtal20[] = {
/* Channel, N, K, mod, R */
{1, 482, 4, 10, 3},
@@ -9417,6 +9974,11 @@ static int rt2800_probe_hw_mode(struct r
spec->channels = rf_vals_3x;
break;
+ case RF3853:
+ spec->num_channels = ARRAY_SIZE(rf_vals_3853);
+ spec->channels = rf_vals_3853;
+ break;
+
case RF5592:
reg = rt2800_register_read(rt2x00dev, MAC_DEBUG_INDEX);
if (rt2x00_get_field32(reg, MAC_DEBUG_INDEX_XTAL)) {
@@ -9536,6 +10098,7 @@ static int rt2800_probe_hw_mode(struct r
case RF3053:
case RF3070:
case RF3290:
+ case RF3853:
case RF5350:
case RF5360:
case RF5362:
@@ -9578,6 +10141,7 @@ static int rt2800_probe_rt(struct rt2x00
case RT3390:
case RT3572:
case RT3593:
+ case RT3883:
case RT5350:
case RT5390:
case RT5392:
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -51,9 +51,16 @@ static bool rt2800soc_hwcrypt_disabled(s
static void rt2800soc_disable_radio(struct rt2x00_dev *rt2x00dev)
{
+ u32 reg;
+
rt2800_disable_radio(rt2x00dev);
rt2x00mmio_register_write(rt2x00dev, PWR_PIN_CFG, 0);
- rt2x00mmio_register_write(rt2x00dev, TX_PIN_CFG, 0);
+
+ reg = 0;
+ if (rt2x00_rt(rt2x00dev, RT3883))
+ rt2x00_set_field32(&reg, TX_PIN_CFG_RFTR_EN, 1);
+
+ rt2x00mmio_register_write(rt2x00dev, TX_PIN_CFG, reg);
}
static int rt2800soc_set_device_state(struct rt2x00_dev *rt2x00dev,

View File

@@ -0,0 +1,56 @@
From 9f3e3323e9966d9f21bea0c81b1acb36c0e15cec Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 15 Jun 2019 12:00:54 +0200
Subject: [PATCH 01/15] rt2x00: allow to specify watchdog interval
Allow subdriver to change watchdog interval by intialize
link->watchdog_interval value before rt2x00link_register().
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 +
drivers/net/wireless/ralink/rt2x00/rt2x00link.c | 13 +++++++++----
2 files changed, 10 insertions(+), 4 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -336,6 +336,7 @@ struct link {
* to bring the device/driver back into the desired state.
*/
struct delayed_work watchdog_work;
+ unsigned int watchdog_interval;
/*
* Work structure for scheduling periodic AGC adjustments.
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
@@ -398,7 +398,7 @@ void rt2x00link_start_watchdog(struct rt
rt2x00dev->ops->lib->watchdog)
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
- WATCHDOG_INTERVAL);
+ link->watchdog_interval);
}
void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
@@ -424,11 +424,16 @@ static void rt2x00link_watchdog(struct w
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
- WATCHDOG_INTERVAL);
+ link->watchdog_interval);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
{
- INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
- INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
+ struct link *link = &rt2x00dev->link;
+
+ INIT_DELAYED_WORK(&link->work, rt2x00link_tuner);
+ INIT_DELAYED_WORK(&link->watchdog_work, rt2x00link_watchdog);
+
+ if (link->watchdog_interval == 0)
+ link->watchdog_interval = WATCHDOG_INTERVAL;
}

View File

@@ -0,0 +1,144 @@
From 2034afe4db4a2a4f22541d7f7b426e38d2093d38 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 15 Jun 2019 12:00:55 +0200
Subject: [PATCH 02/15] rt2800: add helpers for reading dma done index
For mmio we do not properlly trace dma done Q_INDEX_DMA_DONE index
for TX queues. That would require implementing INT_SOURCE_CSR_*_DMA_DONE
interrupts, what is rather not worth to do due to adding extra
CPU load (small but still somewhat not necessary otherwise).
We can just read TX DMA done indexes from registers directly. What
will be used by watchdog.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2800lib.h | 8 +++++
.../net/wireless/ralink/rt2x00/rt2800mmio.c | 31 +++++++++++++++++++
.../net/wireless/ralink/rt2x00/rt2800mmio.h | 2 ++
.../net/wireless/ralink/rt2x00/rt2800pci.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800soc.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800usb.c | 9 ++++++
6 files changed, 52 insertions(+)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -76,6 +76,7 @@ struct rt2800_ops {
const u8 *data, const size_t len);
int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
__le32 *(*drv_get_txwi)(struct queue_entry *entry);
+ unsigned int (*drv_get_dma_done)(struct data_queue *queue);
};
static inline u32 rt2800_register_read(struct rt2x00_dev *rt2x00dev,
@@ -177,6 +178,13 @@ static inline __le32 *rt2800_drv_get_txw
return rt2800ops->drv_get_txwi(entry);
}
+static inline unsigned int rt2800_drv_get_dma_done(struct data_queue *queue)
+{
+ const struct rt2800_ops *rt2800ops = queue->rt2x00dev->ops->drv;
+
+ return rt2800ops->drv_get_dma_done(queue);
+}
+
void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
@@ -36,6 +36,37 @@
#include "rt2800lib.h"
#include "rt2800mmio.h"
+unsigned int rt2800mmio_get_dma_done(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ struct queue_entry *entry;
+ int idx, qid;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ qid = queue->qid;
+ idx = rt2x00mmio_register_read(rt2x00dev, TX_DTX_IDX(qid));
+ break;
+ case QID_MGMT:
+ idx = rt2x00mmio_register_read(rt2x00dev, TX_DTX_IDX(5));
+ break;
+ case QID_RX:
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE);
+ idx = entry->entry_idx;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ idx = 0;
+ break;
+ }
+
+ return idx;
+}
+EXPORT_SYMBOL_GPL(rt2800mmio_get_dma_done);
+
/*
* TX descriptor initialization
*/
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
@@ -126,6 +126,8 @@
#define RXD_W3_PLCP_SIGNAL FIELD32(0x00020000)
#define RXD_W3_PLCP_RSSI FIELD32(0x00040000)
+unsigned int rt2800mmio_get_dma_done(struct data_queue *queue);
+
/* TX descriptor initialization */
__le32 *rt2800mmio_get_txwi(struct queue_entry *entry);
void rt2800mmio_write_tx_desc(struct queue_entry *entry,
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -337,6 +337,7 @@ static const struct rt2800_ops rt2800pci
.drv_write_firmware = rt2800pci_write_firmware,
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
+ .drv_get_dma_done = rt2800mmio_get_dma_done,
};
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -183,6 +183,7 @@ static const struct rt2800_ops rt2800soc
.drv_write_firmware = rt2800soc_write_firmware,
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
+ .drv_get_dma_done = rt2800mmio_get_dma_done,
};
static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = {
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -390,6 +390,14 @@ static int rt2800usb_set_device_state(st
return retval;
}
+static unsigned int rt2800usb_get_dma_done(struct data_queue *queue)
+{
+ struct queue_entry *entry;
+
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE);
+ return entry->entry_idx;
+}
+
/*
* TX descriptor initialization
*/
@@ -672,6 +680,7 @@ static const struct rt2800_ops rt2800usb
.drv_write_firmware = rt2800usb_write_firmware,
.drv_init_registers = rt2800usb_init_registers,
.drv_get_txwi = rt2800usb_get_txwi,
+ .drv_get_dma_done = rt2800usb_get_dma_done,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {

View File

@@ -0,0 +1,158 @@
From 759c5b599cf4ddb3b56e66d459b1bf0fe2724fb8 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 15 Jun 2019 12:00:56 +0200
Subject: [PATCH 03/15] rt2800: initial watchdog implementation
Add watchdog for rt2800 devices. For now it only detect hung
and print error.
[Note: I verified that printing messages from process context is
fine on MT7620 (WT3020) platform that have problem when printk
is called from interrupt context].
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 56 +++++++++++++++++++
.../net/wireless/ralink/rt2x00/rt2800lib.h | 2 +
.../net/wireless/ralink/rt2x00/rt2800pci.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800soc.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800usb.c | 1 +
.../net/wireless/ralink/rt2x00/rt2x00queue.h | 6 ++
6 files changed, 67 insertions(+)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1223,6 +1223,60 @@ void rt2800_txdone_nostatus(struct rt2x0
}
EXPORT_SYMBOL_GPL(rt2800_txdone_nostatus);
+static int rt2800_check_hung(struct data_queue *queue)
+{
+ unsigned int cur_idx = rt2800_drv_get_dma_done(queue);
+
+ if (queue->wd_idx != cur_idx)
+ queue->wd_count = 0;
+ else
+ queue->wd_count++;
+
+ return queue->wd_count > 16;
+}
+
+void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ bool hung_tx = false;
+ bool hung_rx = false;
+
+ if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
+ return;
+
+ queue_for_each(rt2x00dev, queue) {
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ case QID_MGMT:
+ if (rt2x00queue_empty(queue))
+ continue;
+ hung_tx = rt2800_check_hung(queue);
+ break;
+ case QID_RX:
+ /* For station mode we should reactive at least
+ * beacons. TODO: need to find good way detect
+ * RX hung for AP mode.
+ */
+ if (rt2x00dev->intf_sta_count == 0)
+ continue;
+ hung_rx = rt2800_check_hung(queue);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (hung_tx)
+ rt2x00_warn(rt2x00dev, "Watchdog TX hung detected\n");
+
+ if (hung_rx)
+ rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n");
+}
+EXPORT_SYMBOL_GPL(rt2800_watchdog);
+
static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
unsigned int index)
{
@@ -10222,6 +10276,8 @@ int rt2800_probe_hw(struct rt2x00_dev *r
__set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
}
+ rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
+
/*
* Set the rssi offset.
*/
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -208,6 +208,8 @@ void rt2800_txdone_nostatus(struct rt2x0
bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev);
bool rt2800_txstatus_pending(struct rt2x00_dev *rt2x00dev);
+void rt2800_watchdog(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/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -362,6 +362,7 @@ static const struct rt2x00lib_ops rt2800
.link_tuner = rt2800_link_tuner,
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
+ .watchdog = rt2800_watchdog,
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -208,6 +208,7 @@ static const struct rt2x00lib_ops rt2800
.link_tuner = rt2800_link_tuner,
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
+ .watchdog = rt2800_watchdog,
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -698,6 +698,7 @@ static const struct rt2x00lib_ops rt2800
.link_tuner = rt2800_link_tuner,
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
+ .watchdog = rt2800_watchdog,
.start_queue = rt2800usb_start_queue,
.kick_queue = rt2x00usb_kick_queue,
.stop_queue = rt2800usb_stop_queue,
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h
@@ -446,6 +446,9 @@ enum data_queue_flags {
* @length: Number of frames in queue.
* @index: Index pointers to entry positions in the queue,
* use &enum queue_index to get a specific index field.
+ * @wd_count: watchdog counter number of times entry does change
+ * in the queue
+ * @wd_idx: index of queue entry saved by watchdog
* @txop: maximum burst time.
* @aifs: The aifs value for outgoing frames (field ignored in RX queue).
* @cw_min: The cw min value for outgoing frames (field ignored in RX queue).
@@ -473,6 +476,9 @@ struct data_queue {
unsigned short length;
unsigned short index[Q_INDEX_MAX];
+ unsigned short wd_count;
+ unsigned int wd_idx;
+
unsigned short txop;
unsigned short aifs;
unsigned short cw_min;

View File

@@ -0,0 +1,96 @@
From 09db3b000619b38d504e1fff66efed33dfacb6c0 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 15 Jun 2019 12:00:57 +0200
Subject: [PATCH 04/15] rt2800: add pre_reset_hw callback
Add routine to cleanup interfaces data before hw reset as
ieee80211_restart_hw() will do setup interfaces again.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 19 +++++++++++++++++++
.../net/wireless/ralink/rt2x00/rt2800lib.h | 1 +
.../net/wireless/ralink/rt2x00/rt2800pci.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800soc.c | 1 +
.../net/wireless/ralink/rt2x00/rt2800usb.c | 1 +
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 +
6 files changed, 24 insertions(+)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1854,6 +1854,25 @@ int rt2800_sta_remove(struct ieee80211_h
}
EXPORT_SYMBOL_GPL(rt2800_sta_remove);
+void rt2800_pre_reset_hw(struct rt2x00_dev *rt2x00dev)
+{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+ struct data_queue *queue = rt2x00dev->bcn;
+ struct queue_entry *entry;
+ int i, wcid;
+
+ for (wcid = WCID_START; wcid < WCID_END; wcid++) {
+ drv_data->wcid_to_sta[wcid - WCID_START] = NULL;
+ __clear_bit(wcid - WCID_START, drv_data->sta_ids);
+ }
+
+ for (i = 0; i < queue->limit; i++) {
+ entry = &queue->entries[i];
+ clear_bit(ENTRY_BCN_ASSIGNED, &entry->flags);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2800_pre_reset_hw);
+
void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
const unsigned int filter_flags)
{
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -268,5 +268,6 @@ void rt2800_disable_wpdma(struct rt2x00_
void rt2800_get_txwi_rxwi_size(struct rt2x00_dev *rt2x00dev,
unsigned short *txwi_size,
unsigned short *rxwi_size);
+void rt2800_pre_reset_hw(struct rt2x00_dev *rt2x00dev);
#endif /* RT2800LIB_H */
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -379,6 +379,7 @@ static const struct rt2x00lib_ops rt2800
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
+ .pre_reset_hw = rt2800_pre_reset_hw,
};
static const struct rt2x00_ops rt2800pci_ops = {
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -225,6 +225,7 @@ static const struct rt2x00lib_ops rt2800
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
+ .pre_reset_hw = rt2800_pre_reset_hw,
};
static const struct rt2x00_ops rt2800soc_ops = {
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -717,6 +717,7 @@ static const struct rt2x00lib_ops rt2800
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
+ .pre_reset_hw = rt2800_pre_reset_hw,
};
static void rt2800usb_queue_init(struct data_queue *queue)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -627,6 +627,7 @@ struct rt2x00lib_ops {
void (*config) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf,
const unsigned int changed_flags);
+ void (*pre_reset_hw) (struct rt2x00_dev *rt2x00dev);
int (*sta_add) (struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);

View File

@@ -0,0 +1,51 @@
From 710e6cc1595e25378c4b9977f7a8b4ad4a72a109 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 15 Jun 2019 12:00:58 +0200
Subject: [PATCH 05/15] rt2800: do not nullify initialization vector data
If we restart hw we should keep existing IV (initialization vector)
otherwise HW encryption will be broken after restart.
Also fix some coding style issues on the way.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1658,14 +1658,15 @@ static void rt2800_config_wcid_attr_ciph
offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
- memset(&iveiv_entry, 0, sizeof(iveiv_entry));
+ rt2800_register_multiread(rt2x00dev, offset,
+ &iveiv_entry, sizeof(iveiv_entry));
if ((crypto->cipher == CIPHER_TKIP) ||
(crypto->cipher == CIPHER_TKIP_NO_MIC) ||
(crypto->cipher == CIPHER_AES))
iveiv_entry.iv[3] |= 0x20;
iveiv_entry.iv[3] |= key->keyidx << 6;
rt2800_register_multiwrite(rt2x00dev, offset,
- &iveiv_entry, sizeof(iveiv_entry));
+ &iveiv_entry, sizeof(iveiv_entry));
}
int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
@@ -6090,13 +6091,11 @@ static int rt2800_init_registers(struct
* ASIC will keep garbage value after boot, clear encryption keys.
*/
for (i = 0; i < 4; i++)
- rt2800_register_write(rt2x00dev,
- SHARED_KEY_MODE_ENTRY(i), 0);
+ rt2800_register_write(rt2x00dev, SHARED_KEY_MODE_ENTRY(i), 0);
for (i = 0; i < 256; i++) {
rt2800_config_wcid(rt2x00dev, NULL, i);
rt2800_delete_wcid_attr(rt2x00dev, i);
- rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
}
/*

View File

@@ -0,0 +1,151 @@
From e403fa31ed71e87de8e5991e23406b8377c9c894 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 15 Jun 2019 12:00:59 +0200
Subject: [PATCH 06/15] rt2x00: add restart hw
Add ieee80211_restart_hw() to watchdog and debugfs file for testing
if restart works as expected.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 4 +++
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 7 ++++
.../net/wireless/ralink/rt2x00/rt2x00debug.c | 35 +++++++++++++++++++
.../net/wireless/ralink/rt2x00/rt2x00dev.c | 10 ++++--
4 files changed, 54 insertions(+), 2 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1274,6 +1274,9 @@ void rt2800_watchdog(struct rt2x00_dev *
if (hung_rx)
rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n");
+
+ if (hung_tx || hung_rx)
+ ieee80211_restart_hw(rt2x00dev->hw);
}
EXPORT_SYMBOL_GPL(rt2800_watchdog);
@@ -10294,6 +10297,7 @@ int rt2800_probe_hw(struct rt2x00_dev *r
__set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
}
+ __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags);
rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
/*
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -723,6 +723,7 @@ enum rt2x00_capability_flags {
CAPABILITY_VCO_RECALIBRATION,
CAPABILITY_EXTERNAL_PA_TX0,
CAPABILITY_EXTERNAL_PA_TX1,
+ CAPABILITY_RESTART_HW,
};
/*
@@ -1279,6 +1280,12 @@ rt2x00_has_cap_vco_recalibration(struct
return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_VCO_RECALIBRATION);
}
+static inline bool
+rt2x00_has_cap_restart_hw(struct rt2x00_dev *rt2x00dev)
+{
+ return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_RESTART_HW);
+}
+
/**
* rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
* @entry: Pointer to &struct queue_entry
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
@@ -63,6 +63,7 @@ struct rt2x00debug_intf {
* - chipset file
* - device state flags file
* - device capability flags file
+ * - hardware restart file
* - register folder
* - csr offset/value files
* - eeprom offset/value files
@@ -79,6 +80,7 @@ struct rt2x00debug_intf {
struct dentry *chipset_entry;
struct dentry *dev_flags;
struct dentry *cap_flags;
+ struct dentry *restart_hw;
struct dentry *register_folder;
struct dentry *csr_off_entry;
struct dentry *csr_val_entry;
@@ -577,6 +579,34 @@ static const struct file_operations rt2x
.llseek = default_llseek,
};
+static ssize_t rt2x00debug_write_restart_hw(struct file *file,
+ const char __user *buf,
+ size_t length,
+ loff_t *offset)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+ struct rt2x00_dev *rt2x00dev = intf->rt2x00dev;
+ static unsigned long last_reset;
+
+ if (!rt2x00_has_cap_restart_hw(rt2x00dev))
+ return -EOPNOTSUPP;
+
+ if (time_before(jiffies, last_reset + msecs_to_jiffies(2000)))
+ return -EBUSY;
+
+ last_reset = jiffies;
+
+ ieee80211_restart_hw(rt2x00dev->hw);
+ return length;
+}
+
+static const struct file_operations rt2x00debug_restart_hw = {
+ .owner = THIS_MODULE,
+ .write = rt2x00debug_write_restart_hw,
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+};
+
static struct dentry *rt2x00debug_create_file_driver(const char *name,
struct rt2x00debug_intf
*intf,
@@ -672,6 +702,10 @@ void rt2x00debug_register(struct rt2x00_
intf->driver_folder, intf,
&rt2x00debug_fop_cap_flags);
+ intf->restart_hw = debugfs_create_file("restart_hw", 0200,
+ intf->driver_folder, intf,
+ &rt2x00debug_restart_hw);
+
intf->register_folder =
debugfs_create_dir("register", intf->driver_folder);
@@ -753,6 +787,7 @@ void rt2x00debug_deregister(struct rt2x0
debugfs_remove(intf->csr_off_entry);
debugfs_remove(intf->register_folder);
debugfs_remove(intf->dev_flags);
+ debugfs_remove(intf->restart_hw);
debugfs_remove(intf->cap_flags);
debugfs_remove(intf->chipset_entry);
debugfs_remove(intf->driver_entry);
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1269,8 +1269,14 @@ int rt2x00lib_start(struct rt2x00_dev *r
{
int retval;
- if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
- return 0;
+ if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) {
+ /*
+ * This is special case for ieee80211_restart_hw(), otherwise
+ * mac80211 never call start() two times in row without stop();
+ */
+ rt2x00dev->ops->lib->pre_reset_hw(rt2x00dev);
+ rt2x00lib_stop(rt2x00dev);
+ }
/*
* If this is the first interface which is added,

View File

@@ -0,0 +1,71 @@
From 0f47aeeada2a1fe296258eab9a08ced258009481 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 15 Jun 2019 12:01:00 +0200
Subject: [PATCH 07/15] rt2800: do not enable watchdog by default
Make watchdog disabled by default and add module parameter to enable it.
User will have to create file in /etc/modprobe.d/ with
options rt2800lib watchdog=1
to enable the watchdog or load "rt2800lib watchdog=1" module manually
before loading rt2800{soc,pci,usb} module.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 12 ++++++++++--
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 +
drivers/net/wireless/ralink/rt2x00/rt2x00link.c | 2 +-
3 files changed, 12 insertions(+), 3 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -41,6 +41,10 @@
#include "rt2800lib.h"
#include "rt2800.h"
+static bool modparam_watchdog;
+module_param_named(watchdog, modparam_watchdog, bool, S_IRUGO);
+MODULE_PARM_DESC(watchdog, "Enable watchdog to detect tx/rx hangs and reset hardware if detected");
+
/*
* Register access.
* All access to the CSR registers will go through the methods
@@ -10297,8 +10301,12 @@ int rt2800_probe_hw(struct rt2x00_dev *r
__set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
}
- __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags);
- rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
+ if (modparam_watchdog) {
+ __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags);
+ rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
+ } else {
+ rt2x00dev->link.watchdog_disabled = true;
+ }
/*
* Set the rssi offset.
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -337,6 +337,7 @@ struct link {
*/
struct delayed_work watchdog_work;
unsigned int watchdog_interval;
+ bool watchdog_disabled;
/*
* Work structure for scheduling periodic AGC adjustments.
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
@@ -395,7 +395,7 @@ void rt2x00link_start_watchdog(struct rt
struct link *link = &rt2x00dev->link;
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
- rt2x00dev->ops->lib->watchdog)
+ rt2x00dev->ops->lib->watchdog && !link->watchdog_disabled)
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
link->watchdog_interval);

View File

@@ -0,0 +1,67 @@
From 41a531ffa4c5aeb062f892227c00fabb3b4a9c91 Mon Sep 17 00:00:00 2001
From: Soeren Moch <smoch@web.de>
Date: Mon, 1 Jul 2019 12:53:13 +0200
Subject: [PATCH 08/15] rt2x00usb: fix rx queue hang
Since commit ed194d136769 ("usb: core: remove local_irq_save() around
->complete() handler") the handler rt2x00usb_interrupt_rxdone() is
not running with interrupts disabled anymore. So this completion handler
is not guaranteed to run completely before workqueue processing starts
for the same queue entry.
Be sure to set all other flags in the entry correctly before marking
this entry ready for workqueue processing. This way we cannot miss error
conditions that need to be signalled from the completion handler to the
worker thread.
Note that rt2x00usb_work_rxdone() processes all available entries, not
only such for which queue_work() was called.
This patch is similar to what commit df71c9cfceea ("rt2x00: fix order
of entry flags modification") did for TX processing.
This fixes a regression on a RT5370 based wifi stick in AP mode, which
suddenly stopped data transmission after some period of heavy load. Also
stopping the hanging hostapd resulted in the error message "ieee80211
phy0: rt2x00queue_flush_queue: Warning - Queue 14 failed to flush".
Other operation modes are probably affected as well, this just was
the used testcase.
Fixes: ed194d136769 ("usb: core: remove local_irq_save() around ->complete() handler")
Cc: stable@vger.kernel.org # 4.20+
Signed-off-by: Soeren Moch <smoch@web.de>
Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2x00usb.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
@@ -383,15 +383,10 @@ static void rt2x00usb_interrupt_rxdone(s
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
- * Report the frame as DMA done
- */
- rt2x00lib_dmadone(entry);
-
- /*
* Check if the received data is simply too small
* to be actually valid, or if the urb is signaling
* a problem.
@@ -400,6 +395,11 @@ static void rt2x00usb_interrupt_rxdone(s
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
/*
+ * Report the frame as DMA done
+ */
+ rt2x00lib_dmadone(entry);
+
+ /*
* Schedule the delayed work for reading the RX status
* from the device.
*/

View File

@@ -0,0 +1,51 @@
From 3b902fa811cf6bf7f9ad0ffb77d0a133e0b3bd61 Mon Sep 17 00:00:00 2001
From: Soeren Moch <smoch@web.de>
Date: Mon, 1 Jul 2019 12:53:14 +0200
Subject: [PATCH 09/15] rt2x00usb: remove unnecessary rx flag checks
In contrast to the TX path, there is no need to separately read the transfer
status from the device after receiving RX data. Consequently, there is no
real STATUS_PENDING RX processing queue entry state.
Remove the unnecessary ENTRY_DATA_STATUS_PENDING flag checks from the RX path.
Also remove the misleading comment about reading RX status from device.
Suggested-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Soeren Moch <smoch@web.de>
Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2x00usb.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
@@ -360,8 +360,7 @@ static void rt2x00usb_work_rxdone(struct
while (!rt2x00queue_empty(rt2x00dev->rx)) {
entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE);
- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
- !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
break;
/*
@@ -400,8 +399,7 @@ static void rt2x00usb_interrupt_rxdone(s
rt2x00lib_dmadone(entry);
/*
- * Schedule the delayed work for reading the RX status
- * from the device.
+ * Schedule the delayed work for processing RX data
*/
queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work);
}
@@ -413,8 +411,7 @@ static bool rt2x00usb_kick_rx_entry(stru
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
int status;
- if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
- test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
+ if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return false;
rt2x00lib_dmastart(entry);

View File

@@ -0,0 +1,248 @@
From 1dc244064c47d6df7925ca0895f8365e68d3abd1 Mon Sep 17 00:00:00 2001
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: Wed, 3 Jul 2019 13:39:56 +0200
Subject: [PATCH 10/15] rt2x00: no need to check return value of debugfs_create
functions
When calling debugfs functions, there is no need to ever check the
return value. The function can work or not, but the code logic should
never do something different based on this.
Because we don't need to save the individual debugfs files and
directories, remove the local storage of them and just remove the entire
debugfs directory in a single call, making things a lot simpler.
Cc: Stanislaw Gruszka <sgruszka@redhat.com>
Cc: Helmut Schaa <helmut.schaa@googlemail.com>
Cc: Kalle Valo <kvalo@codeaurora.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: linux-wireless@vger.kernel.org
Cc: netdev@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2x00debug.c | 136 +++++-------------
1 file changed, 35 insertions(+), 101 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
@@ -76,26 +76,6 @@ struct rt2x00debug_intf {
* - crypto stats file
*/
struct dentry *driver_folder;
- struct dentry *driver_entry;
- struct dentry *chipset_entry;
- struct dentry *dev_flags;
- struct dentry *cap_flags;
- struct dentry *restart_hw;
- struct dentry *register_folder;
- struct dentry *csr_off_entry;
- struct dentry *csr_val_entry;
- struct dentry *eeprom_off_entry;
- struct dentry *eeprom_val_entry;
- struct dentry *bbp_off_entry;
- struct dentry *bbp_val_entry;
- struct dentry *rf_off_entry;
- struct dentry *rf_val_entry;
- struct dentry *rfcsr_off_entry;
- struct dentry *rfcsr_val_entry;
- struct dentry *queue_folder;
- struct dentry *queue_frame_dump_entry;
- struct dentry *queue_stats_entry;
- struct dentry *crypto_stats_entry;
/*
* The frame dump file only allows a single reader,
@@ -607,39 +587,34 @@ static const struct file_operations rt2x
.llseek = generic_file_llseek,
};
-static struct dentry *rt2x00debug_create_file_driver(const char *name,
- struct rt2x00debug_intf
- *intf,
- struct debugfs_blob_wrapper
- *blob)
+static void rt2x00debug_create_file_driver(const char *name,
+ struct rt2x00debug_intf *intf,
+ struct debugfs_blob_wrapper *blob)
{
char *data;
data = kzalloc(3 * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
- return NULL;
+ return;
blob->data = data;
data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name);
data += sprintf(data, "version:\t%s\n", DRV_VERSION);
blob->size = strlen(blob->data);
- return debugfs_create_blob(name, 0400, intf->driver_folder, blob);
+ debugfs_create_blob(name, 0400, intf->driver_folder, blob);
}
-static struct dentry *rt2x00debug_create_file_chipset(const char *name,
- struct rt2x00debug_intf
- *intf,
- struct
- debugfs_blob_wrapper
- *blob)
+static void rt2x00debug_create_file_chipset(const char *name,
+ struct rt2x00debug_intf *intf,
+ struct debugfs_blob_wrapper *blob)
{
const struct rt2x00debug *debug = intf->debug;
char *data;
data = kzalloc(9 * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
- return NULL;
+ return;
blob->data = data;
data += sprintf(data, "rt chip:\t%04x\n", intf->rt2x00dev->chip.rt);
@@ -665,13 +640,15 @@ static struct dentry *rt2x00debug_create
blob->size = strlen(blob->data);
- return debugfs_create_blob(name, 0400, intf->driver_folder, blob);
+ debugfs_create_blob(name, 0400, intf->driver_folder, blob);
}
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
{
const struct rt2x00debug *debug = rt2x00dev->ops->debugfs;
struct rt2x00debug_intf *intf;
+ struct dentry *queue_folder;
+ struct dentry *register_folder;
intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL);
if (!intf) {
@@ -687,43 +664,27 @@ void rt2x00debug_register(struct rt2x00_
debugfs_create_dir(intf->rt2x00dev->ops->name,
rt2x00dev->hw->wiphy->debugfsdir);
- intf->driver_entry =
- rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);
-
- intf->chipset_entry =
- rt2x00debug_create_file_chipset("chipset",
- intf, &intf->chipset_blob);
-
- intf->dev_flags = debugfs_create_file("dev_flags", 0400,
- intf->driver_folder, intf,
- &rt2x00debug_fop_dev_flags);
-
- intf->cap_flags = debugfs_create_file("cap_flags", 0400,
- intf->driver_folder, intf,
- &rt2x00debug_fop_cap_flags);
-
- intf->restart_hw = debugfs_create_file("restart_hw", 0200,
- intf->driver_folder, intf,
- &rt2x00debug_restart_hw);
+ rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);
+ rt2x00debug_create_file_chipset("chipset", intf, &intf->chipset_blob);
+ debugfs_create_file("dev_flags", 0400, intf->driver_folder, intf,
+ &rt2x00debug_fop_dev_flags);
+ debugfs_create_file("cap_flags", 0400, intf->driver_folder, intf,
+ &rt2x00debug_fop_cap_flags);
+ debugfs_create_file("restart_hw", 0200, intf->driver_folder, intf,
+ &rt2x00debug_restart_hw);
- intf->register_folder =
- debugfs_create_dir("register", intf->driver_folder);
+ register_folder = debugfs_create_dir("register", intf->driver_folder);
#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \
({ \
if (debug->__name.read) { \
- (__intf)->__name##_off_entry = \
- debugfs_create_u32(__stringify(__name) "_offset", \
- 0600, \
- (__intf)->register_folder, \
- &(__intf)->offset_##__name); \
+ debugfs_create_u32(__stringify(__name) "_offset", 0600, \
+ register_folder, \
+ &(__intf)->offset_##__name); \
\
- (__intf)->__name##_val_entry = \
- debugfs_create_file(__stringify(__name) "_value", \
- 0600, \
- (__intf)->register_folder, \
- (__intf), \
- &rt2x00debug_fop_##__name); \
+ debugfs_create_file(__stringify(__name) "_value", 0600, \
+ register_folder, (__intf), \
+ &rt2x00debug_fop_##__name); \
} \
})
@@ -735,26 +696,21 @@ void rt2x00debug_register(struct rt2x00_
#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY
- intf->queue_folder =
- debugfs_create_dir("queue", intf->driver_folder);
+ queue_folder = debugfs_create_dir("queue", intf->driver_folder);
- intf->queue_frame_dump_entry =
- debugfs_create_file("dump", 0400, intf->queue_folder,
- intf, &rt2x00debug_fop_queue_dump);
+ debugfs_create_file("dump", 0400, queue_folder, intf,
+ &rt2x00debug_fop_queue_dump);
skb_queue_head_init(&intf->frame_dump_skbqueue);
init_waitqueue_head(&intf->frame_dump_waitqueue);
- intf->queue_stats_entry =
- debugfs_create_file("queue", 0400, intf->queue_folder,
- intf, &rt2x00debug_fop_queue_stats);
+ debugfs_create_file("queue", 0400, queue_folder, intf,
+ &rt2x00debug_fop_queue_stats);
#ifdef CPTCFG_RT2X00_LIB_CRYPTO
if (rt2x00_has_cap_hw_crypto(rt2x00dev))
- intf->crypto_stats_entry =
- debugfs_create_file("crypto", 0444, intf->queue_folder,
- intf,
- &rt2x00debug_fop_crypto_stats);
+ debugfs_create_file("crypto", 0444, queue_folder, intf,
+ &rt2x00debug_fop_crypto_stats);
#endif
return;
@@ -769,31 +725,7 @@ void rt2x00debug_deregister(struct rt2x0
skb_queue_purge(&intf->frame_dump_skbqueue);
-#ifdef CPTCFG_RT2X00_LIB_CRYPTO
- debugfs_remove(intf->crypto_stats_entry);
-#endif
- debugfs_remove(intf->queue_stats_entry);
- debugfs_remove(intf->queue_frame_dump_entry);
- debugfs_remove(intf->queue_folder);
- debugfs_remove(intf->rfcsr_val_entry);
- debugfs_remove(intf->rfcsr_off_entry);
- debugfs_remove(intf->rf_val_entry);
- debugfs_remove(intf->rf_off_entry);
- debugfs_remove(intf->bbp_val_entry);
- debugfs_remove(intf->bbp_off_entry);
- debugfs_remove(intf->eeprom_val_entry);
- debugfs_remove(intf->eeprom_off_entry);
- debugfs_remove(intf->csr_val_entry);
- debugfs_remove(intf->csr_off_entry);
- debugfs_remove(intf->register_folder);
- debugfs_remove(intf->dev_flags);
- debugfs_remove(intf->restart_hw);
- debugfs_remove(intf->cap_flags);
- debugfs_remove(intf->chipset_entry);
- debugfs_remove(intf->driver_entry);
- debugfs_remove(intf->driver_folder);
- kfree(intf->chipset_blob.data);
- kfree(intf->driver_blob.data);
+ debugfs_remove_recursive(intf->driver_folder);
kfree(intf);
rt2x00dev->debugfs_intf = NULL;

View File

@@ -0,0 +1,29 @@
From 706f0182b1add0fc41a8c40662f659b7426f0629 Mon Sep 17 00:00:00 2001
From: Masanari Iida <standby24x7@gmail.com>
Date: Sun, 28 Jul 2019 23:07:42 +0900
Subject: [PATCH 11/15] rt2800usb: Add new rt2800usb device PLANEX GW-USMicroN
This patch add a device ID for PLANEX GW-USMicroN.
Without this patch, I had to echo the device IDs in order to
recognize the device.
# lsusb |grep PLANEX
Bus 002 Device 005: ID 2019:ed14 PLANEX GW-USMicroN
Signed-off-by: Masanari Iida <standby24x7@gmail.com>
Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800usb.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -1097,6 +1097,7 @@ static const struct usb_device_id rt2800
{ USB_DEVICE(0x0846, 0x9013) },
{ USB_DEVICE(0x0846, 0x9019) },
/* Planex */
+ { USB_DEVICE(0x2019, 0xed14) },
{ USB_DEVICE(0x2019, 0xed19) },
/* Ralink */
{ USB_DEVICE(0x148f, 0x3573) },

View File

@@ -0,0 +1,102 @@
From 95844124385eae4bd9ca5f9514a0fc33d561ac3c Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Mon, 19 Aug 2019 13:20:07 +0200
Subject: [PATCH 12/15] rt2x00: clear IV's on start to fix AP mode regression
To do not brake HW restart we should keep initialization vectors data.
I assumed that on start the data is already initialized to zeros, but
that not true on some scenarios and we should clear it. So add
additional flag to check if we are under HW restart and clear IV's
data if we are not.
Patch fixes AP mode regression.
Reported-and-tested-by: Emil Karlson <jekarl@iki.fi>
Fixes: 710e6cc1595e ("rt2800: do not nullify initialization vector data")
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 9 +++++++++
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 +
drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 13 ++++++++-----
3 files changed, 18 insertions(+), 5 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -6106,6 +6106,15 @@ static int rt2800_init_registers(struct
}
/*
+ * Clear encryption initialization vectors on start, but keep them
+ * for watchdog reset. Otherwise we will have wrong IVs and not be
+ * able to keep connections after reset.
+ */
+ if (!test_bit(DEVICE_STATE_RESET, &rt2x00dev->flags))
+ for (i = 0; i < 256; i++)
+ rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
+
+ /*
* Clear all beacons
*/
for (i = 0; i < 8; i++)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -669,6 +669,7 @@ enum rt2x00_state_flags {
DEVICE_STATE_ENABLED_RADIO,
DEVICE_STATE_SCANNING,
DEVICE_STATE_FLUSHING,
+ DEVICE_STATE_RESET,
/*
* Driver configuration
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1267,13 +1267,14 @@ static int rt2x00lib_initialize(struct r
int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
{
- int retval;
+ int retval = 0;
if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) {
/*
* This is special case for ieee80211_restart_hw(), otherwise
* mac80211 never call start() two times in row without stop();
*/
+ set_bit(DEVICE_STATE_RESET, &rt2x00dev->flags);
rt2x00dev->ops->lib->pre_reset_hw(rt2x00dev);
rt2x00lib_stop(rt2x00dev);
}
@@ -1284,14 +1285,14 @@ int rt2x00lib_start(struct rt2x00_dev *r
*/
retval = rt2x00lib_load_firmware(rt2x00dev);
if (retval)
- return retval;
+ goto out;
/*
* Initialize the device.
*/
retval = rt2x00lib_initialize(rt2x00dev);
if (retval)
- return retval;
+ goto out;
rt2x00dev->intf_ap_count = 0;
rt2x00dev->intf_sta_count = 0;
@@ -1300,11 +1301,13 @@ int rt2x00lib_start(struct rt2x00_dev *r
/* Enable the radio */
retval = rt2x00lib_enable_radio(rt2x00dev);
if (retval)
- return retval;
+ goto out;
set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags);
- return 0;
+out:
+ clear_bit(DEVICE_STATE_RESET, &rt2x00dev->flags);
+ return retval;
}
void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev)

View File

@@ -0,0 +1,40 @@
From 567a9b766b47caffe4b1bf74823e7bc18532d875 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Fri, 23 Aug 2019 09:09:56 +0200
Subject: [PATCH 13/15] rt2x00: do not set IEEE80211_TX_STAT_AMPDU_NO_BACK on
tx status
According to documentation IEEE80211_TX_STAT_AMPDU_NO_BACK is suppose
to be used when we do not recive BA (BlockAck). However on rt2x00 we
use it when remote station fail to decode one or more subframes within
AMPDU (some bits are not set in BlockAck bitmap). Setting the flag result
in sent of BAR (BlockAck Request) frame and this might result of abuse
of BA session, since remote station can sent BA with incorrect
sequence numbers after receiving BAR. This problem is visible especially
when connecting two rt2800 devices.
Previously I observed some performance benefits when using the flag
when connecting with iwlwifi devices. But currently possibly due
to reacent changes in rt2x00 removing the flag has no effect on
those test cases.
So remove the IEEE80211_TX_STAT_AMPDU_NO_BACK.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 3 ---
1 file changed, 3 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -382,9 +382,6 @@ static void rt2x00lib_fill_tx_status(str
IEEE80211_TX_CTL_AMPDU;
tx_info->status.ampdu_len = 1;
tx_info->status.ampdu_ack_len = success ? 1 : 0;
-
- if (!success)
- tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
}
if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {

View File

@@ -0,0 +1,46 @@
From 14d5e14c8a6c257eb322ddeb294ac4c243a7d2e1 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Fri, 23 Aug 2019 14:48:03 +0200
Subject: [PATCH 14/15] rt2x00: clear up IV's on key removal
After looking at code I realized that my previous fix
95844124385e ("rt2x00: clear IV's on start to fix AP mode regression")
was incomplete. We can still have wrong IV's after re-keyring.
To fix that, clear up IV's also on key removal.
Fixes: 710e6cc1595e ("rt2800: do not nullify initialization vector data")
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
tested-by: Emil Karlson <jekarl@iki.fi>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/ralink/rt2x00/rt2800lib.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1665,13 +1665,18 @@ static void rt2800_config_wcid_attr_ciph
offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
- rt2800_register_multiread(rt2x00dev, offset,
- &iveiv_entry, sizeof(iveiv_entry));
- if ((crypto->cipher == CIPHER_TKIP) ||
- (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
- (crypto->cipher == CIPHER_AES))
- iveiv_entry.iv[3] |= 0x20;
- iveiv_entry.iv[3] |= key->keyidx << 6;
+ if (crypto->cmd == SET_KEY) {
+ rt2800_register_multiread(rt2x00dev, offset,
+ &iveiv_entry, sizeof(iveiv_entry));
+ if ((crypto->cipher == CIPHER_TKIP) ||
+ (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
+ (crypto->cipher == CIPHER_AES))
+ iveiv_entry.iv[3] |= 0x20;
+ iveiv_entry.iv[3] |= key->keyidx << 6;
+ } else {
+ memset(&iveiv_entry, 0, sizeof(iveiv_entry));
+ }
+
rt2800_register_multiwrite(rt2x00dev, offset,
&iveiv_entry, sizeof(iveiv_entry));
}

View File

@@ -0,0 +1,61 @@
From 13fa451568ab9e8b3074ef741477c7938c713c42 Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Thu, 29 Aug 2019 13:29:59 +0200
Subject: [PATCH 15/15] Revert "rt2800: enable TX_PIN_CFG_LNA_PE_ bits per
band"
This reverts commit 9ad3b55654455258a9463384edb40077439d879f.
As reported by Sergey:
"I got some problem after upgrade kernel to 5.2 version (debian testing
linux-image-5.2.0-2-amd64). 5Ghz client stopped to see AP.
Some tests with 1metre distance between client-AP: 2.4Ghz -22dBm, for
5Ghz - 53dBm !, for longer distance (8m + walls) 2.4 - 61dBm, 5Ghz not
visible."
It was identified that rx signal level degradation was caused by
9ad3b5565445 ("rt2800: enable TX_PIN_CFG_LNA_PE_ bits per band").
So revert this commit.
Cc: <stable@vger.kernel.org> # v5.1+
Reported-and-tested-by: Sergey Maranchuk <slav0nic0@gmail.com>
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -4253,24 +4253,18 @@ static void rt2800_config_channel(struct
switch (rt2x00dev->default_ant.rx_chain_num) {
case 3:
/* Turn on tertiary LNAs */
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A2_EN,
- rf->channel > 14);
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G2_EN,
- rf->channel <= 14);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A2_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G2_EN, 1);
/* fall-through */
case 2:
/* Turn on secondary LNAs */
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN,
- rf->channel > 14);
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN,
- rf->channel <= 14);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1);
/* fall-through */
case 1:
/* Turn on primary LNAs */
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN,
- rf->channel > 14);
- rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN,
- rf->channel <= 14);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1);
break;
}

View File

@@ -0,0 +1,88 @@
From patchwork Sat Nov 2 17:47:01 2019
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
X-Patchwork-Id: 11224189
X-Patchwork-Delegate: kvalo@adurom.com
Return-Path: <SRS0=CgQo=Y2=vger.kernel.org=linux-wireless-owner@kernel.org>
Date: Sat, 2 Nov 2019 18:47:01 +0100
From: Daniel Golle <daniel@makrotopia.org>
To: Stanislaw Gruszka <sgruszka@redhat.com>
Cc: linux-wireless@vger.kernel.org, Roman Yeryomin <roman@advem.lv>,
wbob <wbob@jify.de>
Subject: [PATCH v2] rt2800: remove errornous duplicate condition
Message-ID: <20191102174701.GA1489@makrotopia.org>
References: <20191102154639.GA4589@redhat.com>
MIME-Version: 1.0
Content-Disposition: inline
In-Reply-To: <20191102154639.GA4589@redhat.com>
User-Agent: Mutt/1.12.2 (2019-09-21)
Sender: linux-wireless-owner@vger.kernel.org
Precedence: bulk
List-ID: <linux-wireless.vger.kernel.org>
X-Mailing-List: linux-wireless@vger.kernel.org
On 2019-10-28 06:07, wbob wrote:
> Hello Roman,
>
> while reading around drivers/net/wireless/ralink/rt2x00/rt2800lib.c
> I stumbled on what I think is an edit of yours made in error in march
> 2017:
>
> https://github.com/torvalds/linux/commit/41977e86#diff-dae5dc10da180f3b055809a48118e18aR5281
>
> RT6352 in line 5281 should not have been introduced as the "else if"
> below line 5291 can then not take effect for a RT6352 device. Another
> possibility is for line 5291 to be not for RT6352, but this seems
> very unlikely. Are you able to clarify still after this substantial time?
>
> 5277: static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
> ...
> 5279: } else if (rt2x00_rt(rt2x00dev, RT5390) ||
> 5280: rt2x00_rt(rt2x00dev, RT5392) ||
> 5281: rt2x00_rt(rt2x00dev, RT6352)) {
> ...
> 5291: } else if (rt2x00_rt(rt2x00dev, RT6352)) {
> ...
Hence remove errornous line 5281 to make the driver actually
execute the correct initialization routine for MT7620 chips.
As it was requested by Stanislaw Gruszka remove setting values of
MIMO_PS_CFG and TX_PIN_CFG. MIMO_PS_CFG is responsible for MIMO
power-safe mode (which is disabled), hence we can drop setting it.
TX_PIN_CFG is set correctly in other functions, and as setting this
value breaks some devices, rather don't set it here during init, but
only modify it later on.
Fixes: 41977e86c984 ("rt2x00: add support for MT7620")
Reported-by: wbob <wbob@jify.de>
Reported-by: Roman Yeryomin <roman@advem.lv>
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -5850,8 +5850,7 @@ static int rt2800_init_registers(struct
rt2800_register_write(rt2x00dev, TX_TXBF_CFG_0, 0x8000fc21);
rt2800_register_write(rt2x00dev, TX_TXBF_CFG_3, 0x00009c40);
} else if (rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392) ||
- rt2x00_rt(rt2x00dev, RT6352)) {
+ rt2x00_rt(rt2x00dev, RT5392)) {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
@@ -5865,8 +5864,6 @@ static int rt2800_init_registers(struct
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0000);
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
- rt2800_register_write(rt2x00dev, MIMO_PS_CFG, 0x00000002);
- rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0x00150F0F);
rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000);
rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0);
rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, 0x0);

View File

@@ -0,0 +1,47 @@
--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
+++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
@@ -225,36 +225,37 @@ config RT2800SOC
config RT2800_LIB
- tristate
+ tristate "RT2800 USB/PCI support"
depends on m
config RT2800_LIB_MMIO
- tristate
+ tristate "RT2800 MMIO support"
depends on m
select RT2X00_LIB_MMIO
select RT2800_LIB
config RT2X00_LIB_MMIO
- tristate
+ tristate "RT2x00 MMIO support"
depends on m
config RT2X00_LIB_PCI
- tristate
+ tristate "RT2x00 PCI support"
depends on m
select RT2X00_LIB
config RT2X00_LIB_SOC
- tristate
+ tristate "RT2x00 SoC support"
+ depends on SOC_RT288X || SOC_RT305X || SOC_MT7620
depends on m
select RT2X00_LIB
config RT2X00_LIB_USB
- tristate
+ tristate "RT2x00 USB support"
depends on m
select RT2X00_LIB
config RT2X00_LIB
- tristate
+ tristate "RT2x00 support"
depends on m
config RT2X00_LIB_FIRMWARE

View File

@@ -0,0 +1,30 @@
From 91094ed065f7794886b4a5490fd6de942f036bb4 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Sun, 24 Mar 2013 19:26:26 +0100
Subject: [PATCH] rt2x00: allow to build rt2800soc module for RT3883
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
drivers/net/wireless/ralink/rt2x00/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
+++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
@@ -210,7 +210,7 @@ endif
config RT2800SOC
tristate "Ralink WiSoC support"
depends on m
- depends on SOC_RT288X || SOC_RT305X || SOC_MT7620
+ depends on SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620
select RT2X00_LIB_SOC
select RT2X00_LIB_MMIO
select RT2X00_LIB_CRYPTO
@@ -245,7 +245,7 @@ config RT2X00_LIB_PCI
config RT2X00_LIB_SOC
tristate "RT2x00 SoC support"
- depends on SOC_RT288X || SOC_RT305X || SOC_MT7620
+ depends on SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620
depends on m
select RT2X00_LIB

View File

@@ -0,0 +1,32 @@
--- /dev/null
+++ b/include/linux/rt2x00_platform.h
@@ -0,0 +1,19 @@
+/*
+ * Platform data definition for the rt2x00 driver
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#ifndef _RT2X00_PLATFORM_H
+#define _RT2X00_PLATFORM_H
+
+struct rt2x00_platform_data {
+ char *eeprom_file_name;
+};
+
+#endif /* _RT2X00_PLATFORM_H */
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -40,6 +40,7 @@
#include <linux/average.h>
#include <linux/usb.h>
#include <linux/clk.h>
+#include <linux/rt2x00_platform.h>
#include <net/mac80211.h>

View File

@@ -0,0 +1,296 @@
--- a/local-symbols
+++ b/local-symbols
@@ -305,6 +305,7 @@ RT2X00_LIB_FIRMWARE=
RT2X00_LIB_CRYPTO=
RT2X00_LIB_LEDS=
RT2X00_LIB_DEBUGFS=
+RT2X00_LIB_EEPROM=
RT2X00_DEBUG=
WLAN_VENDOR_REALTEK=
RTL8180=
--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
+++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
@@ -69,6 +69,7 @@ config RT2800PCI
select RT2X00_LIB_MMIO
select RT2X00_LIB_PCI
select RT2X00_LIB_FIRMWARE
+ select RT2X00_LIB_EEPROM
select RT2X00_LIB_CRYPTO
depends on CRC_CCITT
depends on EEPROM_93CX6
@@ -215,6 +216,7 @@ config RT2800SOC
select RT2X00_LIB_MMIO
select RT2X00_LIB_CRYPTO
select RT2X00_LIB_FIRMWARE
+ select RT2X00_LIB_EEPROM
select RT2800_LIB
select RT2800_LIB_MMIO
---help---
@@ -265,6 +267,9 @@ config RT2X00_LIB_FIRMWARE
config RT2X00_LIB_CRYPTO
bool
+config RT2X00_LIB_EEPROM
+ boolean
+
config RT2X00_LIB_LEDS
bool
default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
--- a/drivers/net/wireless/ralink/rt2x00/Makefile
+++ b/drivers/net/wireless/ralink/rt2x00/Makefile
@@ -8,6 +8,7 @@ rt2x00lib-$(CPTCFG_RT2X00_LIB_DEBUGFS) +
rt2x00lib-$(CPTCFG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
rt2x00lib-$(CPTCFG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
rt2x00lib-$(CPTCFG_RT2X00_LIB_LEDS) += rt2x00leds.o
+rt2x00lib-$(CPTCFG_RT2X00_LIB_EEPROM) += rt2x00eeprom.o
obj-$(CPTCFG_RT2X00_LIB) += rt2x00lib.o
obj-$(CPTCFG_RT2X00_LIB_MMIO) += rt2x00mmio.o
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -48,6 +48,8 @@ struct rt2800_drv_data {
struct ieee80211_sta *wcid_to_sta[STA_IDS_SIZE];
};
+#include "rt2800.h"
+
struct rt2800_ops {
u32 (*register_read)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset);
@@ -146,6 +148,15 @@ static inline int rt2800_read_eeprom(str
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
+ if (rt2x00dev->eeprom_file) {
+ memcpy(rt2x00dev->eeprom, rt2x00dev->eeprom_file->data,
+ EEPROM_SIZE);
+ return 0;
+ }
+
+ if (!rt2800ops->read_eeprom)
+ return -EINVAL;
+
return rt2800ops->read_eeprom(rt2x00dev);
}
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -102,19 +102,6 @@ static int rt2800soc_set_device_state(st
return retval;
}
-static int rt2800soc_read_eeprom(struct rt2x00_dev *rt2x00dev)
-{
- void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE);
-
- if (!base_addr)
- return -ENOMEM;
-
- memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
-
- iounmap(base_addr);
- return 0;
-}
-
/* Firmware functions */
static char *rt2800soc_get_firmware_name(struct rt2x00_dev *rt2x00dev)
{
@@ -178,7 +165,6 @@ static const struct rt2800_ops rt2800soc
.register_multiread = rt2x00mmio_register_multiread,
.register_multiwrite = rt2x00mmio_register_multiwrite,
.regbusy_read = rt2x00mmio_regbusy_read,
- .read_eeprom = rt2800soc_read_eeprom,
.hwcrypt_disabled = rt2800soc_hwcrypt_disabled,
.drv_write_firmware = rt2800soc_write_firmware,
.drv_init_registers = rt2800mmio_init_registers,
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -706,6 +706,7 @@ enum rt2x00_capability_flags {
REQUIRE_HT_TX_DESC,
REQUIRE_PS_AUTOWAKE,
REQUIRE_DELAYED_RFKILL,
+ REQUIRE_EEPROM_FILE,
/*
* Capabilities
@@ -982,6 +983,11 @@ struct rt2x00_dev {
const struct firmware *fw;
/*
+ * EEPROM image.
+ */
+ const struct firmware *eeprom_file;
+
+ /*
* FIFO for storing tx status reports between isr and tasklet.
*/
DECLARE_KFIFO_PTR(txstatus_fifo, u32);
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1429,6 +1429,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);
+ retval = rt2x00lib_load_eeprom_file(rt2x00dev);
+ if (retval)
+ goto exit;
+
/*
* Let the driver probe the device to detect the capabilities.
*/
@@ -1572,6 +1576,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
* Free the driver data.
*/
kfree(rt2x00dev->drv_data);
+
+ /*
+ * Free EEPROM image.
+ */
+ rt2x00lib_free_eeprom_file(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);
--- /dev/null
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c
@@ -0,0 +1,106 @@
+/*
+ Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 eeprom file loading routines.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+static const char *
+rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
+{
+ struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data;
+
+ if (pdata && pdata->eeprom_file_name)
+ return pdata->eeprom_file_name;
+
+ return NULL
+}
+
+static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev)
+{
+ const struct firmware *ee;
+ const char *ee_name;
+ int retval;
+
+ ee_name = rt2x00lib_get_eeprom_file_name(rt2x00dev);
+ if (!ee_name && test_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags)) {
+ rt2x00_err(rt2x00dev, "Required EEPROM name is missing.");
+ return -EINVAL;
+ }
+
+ if (!ee_name)
+ return 0;
+
+ rt2x00_info(rt2x00dev, "Loading EEPROM data from '%s'.\n", ee_name);
+
+ retval = request_firmware(&ee, ee_name, rt2x00dev->dev);
+ if (retval) {
+ rt2x00_err(rt2x00dev, "Failed to request EEPROM.\n");
+ return retval;
+ }
+
+ if (!ee || !ee->size || !ee->data) {
+ rt2x00_err(rt2x00dev, "Failed to read EEPROM file.\n");
+ retval = -ENOENT;
+ goto err_exit;
+ }
+
+ if (ee->size != rt2x00dev->ops->eeprom_size) {
+ rt2x00_err(rt2x00dev,
+ "EEPROM file size is invalid, it should be %d bytes\n",
+ rt2x00dev->ops->eeprom_size);
+ retval = -EINVAL;
+ goto err_release_ee;
+ }
+
+ rt2x00dev->eeprom_file = ee;
+ return 0;
+
+err_release_ee:
+ release_firmware(ee);
+err_exit:
+ return retval;
+}
+
+int rt2x00lib_load_eeprom_file(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ retval = rt2x00lib_request_eeprom_file(rt2x00dev);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
+void rt2x00lib_free_eeprom_file(struct rt2x00_dev *rt2x00dev)
+{
+ if (rt2x00dev->eeprom_file && rt2x00dev->eeprom_file->size)
+ release_firmware(rt2x00dev->eeprom_file);
+ rt2x00dev->eeprom_file = NULL;
+}
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00lib.h
@@ -297,6 +297,22 @@ static inline void rt2x00lib_free_firmwa
#endif /* CPTCFG_RT2X00_LIB_FIRMWARE */
/*
+ * EEPROM file handlers.
+ */
+#ifdef CPTCFG_RT2X00_LIB_EEPROM
+int rt2x00lib_load_eeprom_file(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_free_eeprom_file(struct rt2x00_dev *rt2x00dev);
+#else
+static inline int rt2x00lib_load_eeprom_file(struct rt2x00_dev *rt2x00dev)
+{
+ return 0;
+}
+static inline void rt2x00lib_free_eeprom_file(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CPTCFG_RT2X00_LIB_EEPROM */
+
+/*
* Debugfs handlers.
*/
#ifdef CPTCFG_RT2X00_LIB_DEBUGFS
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c
@@ -97,6 +97,7 @@ int rt2x00soc_probe(struct platform_devi
if (IS_ERR(rt2x00dev->clk))
rt2x00dev->clk = NULL;
+ set_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags);
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC);
retval = rt2x00soc_alloc_reg(rt2x00dev);

View File

@@ -0,0 +1,33 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
@@ -34,11 +35,21 @@ static const char *
rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
{
struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data;
+#ifdef CONFIG_OF
+ struct device_node *np;
+ const char *eep;
+#endif
if (pdata && pdata->eeprom_file_name)
return pdata->eeprom_file_name;
- return NULL
+#ifdef CONFIG_OF
+ np = rt2x00dev->dev->of_node;
+ if (np && of_property_read_string(np, "ralink,eeprom", &eep) == 0)
+ return eep;
+#endif
+
+ return NULL;
}
static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev)

View File

@@ -0,0 +1,107 @@
From 339fe73f340161a624cc08e738d2244814852c3e Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 17 Mar 2013 00:55:04 +0100
Subject: [PATCH] rt2x00: load eeprom on SoC from a mtd device defines inside
OF
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/net/wireless/ralink/rt2x00/Kconfig | 1 +
drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c | 65 +++++++++++++++++++++++
2 files changed, 66 insertions(+)
--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
+++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
@@ -219,6 +219,7 @@ config RT2800SOC
select RT2X00_LIB_EEPROM
select RT2800_LIB
select RT2800_LIB_MMIO
+ select MTD if SOC_RT288X || SOC_RT305X
---help---
This adds support for Ralink WiSoC devices.
Supported chips: RT2880, RT3050, RT3052, RT3350, RT3352.
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c
@@ -26,11 +26,72 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
#include <linux/of.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
+static int rt2800lib_read_eeprom_mtd(struct rt2x00_dev *rt2x00dev)
+{
+ int ret = -EINVAL;
+#ifdef CONFIG_OF
+ static struct firmware mtd_fw;
+ struct device_node *np = rt2x00dev->dev->of_node, *mtd_np = NULL;
+ size_t retlen, len = rt2x00dev->ops->eeprom_size;
+ int i, size, offset = 0;
+ struct mtd_info *mtd;
+ const char *part;
+ const __be32 *list;
+ phandle phandle;
+
+ list = of_get_property(np, "ralink,mtd-eeprom", &size);
+ if (!list)
+ return -ENOENT;
+
+ phandle = be32_to_cpup(list++);
+ if (phandle)
+ mtd_np = of_find_node_by_phandle(phandle);
+ if (!mtd_np) {
+ dev_err(rt2x00dev->dev, "failed to load mtd phandle\n");
+ return -EINVAL;
+ }
+
+ part = of_get_property(mtd_np, "label", NULL);
+ if (!part)
+ part = mtd_np->name;
+
+ mtd = get_mtd_device_nm(part);
+ if (IS_ERR(mtd)) {
+ dev_err(rt2x00dev->dev, "failed to get mtd device \"%s\"\n", part);
+ return PTR_ERR(mtd);
+ }
+
+ if (size > sizeof(*list))
+ offset = be32_to_cpup(list);
+
+ ret = mtd_read(mtd, offset, len, &retlen, (u_char *) rt2x00dev->eeprom);
+ put_mtd_device(mtd);
+
+ if ((retlen != rt2x00dev->ops->eeprom_size) || ret) {
+ dev_err(rt2x00dev->dev, "failed to load eeprom from device \"%s\"\n", part);
+ return ret;
+ }
+
+ if (of_find_property(np, "ralink,mtd-eeprom-swap", NULL))
+ for (i = 0; i < len/sizeof(u16); i++)
+ rt2x00dev->eeprom[i] = swab16(rt2x00dev->eeprom[i]);
+
+ rt2x00dev->eeprom_file = &mtd_fw;
+ mtd_fw.data = (const u8 *) rt2x00dev->eeprom;
+
+ dev_info(rt2x00dev->dev, "loaded eeprom from mtd device \"%s\"\n", part);
+#endif
+
+ return ret;
+}
+
static const char *
rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
{
@@ -58,6 +119,9 @@ static int rt2x00lib_request_eeprom_file
const char *ee_name;
int retval;
+ if (!rt2800lib_read_eeprom_mtd(rt2x00dev))
+ return 0;
+
ee_name = rt2x00lib_get_eeprom_file_name(rt2x00dev);
if (!ee_name && test_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags)) {
rt2x00_err(rt2x00dev, "Required EEPROM name is missing.");

View File

@@ -0,0 +1,47 @@
--- a/include/linux/rt2x00_platform.h
+++ b/include/linux/rt2x00_platform.h
@@ -14,6 +14,9 @@
struct rt2x00_platform_data {
char *eeprom_file_name;
+
+ int disable_2ghz;
+ int disable_5ghz;
};
#endif /* _RT2X00_PLATFORM_H */
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1023,6 +1023,22 @@ static int rt2x00lib_probe_hw_modes(stru
unsigned int num_rates;
unsigned int i;
+ if (rt2x00dev->dev->platform_data) {
+ struct rt2x00_platform_data *pdata;
+
+ pdata = rt2x00dev->dev->platform_data;
+ if (pdata->disable_2ghz)
+ spec->supported_bands &= ~SUPPORT_BAND_2GHZ;
+ if (pdata->disable_5ghz)
+ spec->supported_bands &= ~SUPPORT_BAND_5GHZ;
+ }
+
+ if ((spec->supported_bands & SUPPORT_BAND_BOTH) == 0) {
+ rt2x00_err(rt2x00dev, "No supported bands\n");
+ return -EINVAL;
+ }
+
+
num_rates = 0;
if (spec->supported_rates & SUPPORT_RATE_CCK)
num_rates += 4;
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -411,6 +411,7 @@ struct hw_mode_spec {
unsigned int supported_bands;
#define SUPPORT_BAND_2GHZ 0x00000001
#define SUPPORT_BAND_5GHZ 0x00000002
+#define SUPPORT_BAND_BOTH (SUPPORT_BAND_2GHZ | SUPPORT_BAND_5GHZ)
unsigned int supported_rates;
#define SUPPORT_RATE_CCK 0x00000001

View File

@@ -0,0 +1,26 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1001,8 +1001,13 @@ static void rt2x00lib_rate(struct ieee80
void rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr)
{
+ struct rt2x00_platform_data *pdata;
const char *mac_addr;
+ pdata = rt2x00dev->dev->platform_data;
+ if (pdata && pdata->mac_address)
+ ether_addr_copy(eeprom_mac_addr, pdata->mac_address);
+
mac_addr = of_get_mac_address(rt2x00dev->dev->of_node);
if (mac_addr)
ether_addr_copy(eeprom_mac_addr, mac_addr);
--- a/include/linux/rt2x00_platform.h
+++ b/include/linux/rt2x00_platform.h
@@ -14,6 +14,7 @@
struct rt2x00_platform_data {
char *eeprom_file_name;
+ const u8 *mac_address;
int disable_2ghz;
int disable_5ghz;

View File

@@ -0,0 +1,19 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1027,6 +1027,16 @@ static int rt2x00lib_probe_hw_modes(stru
struct ieee80211_rate *rates;
unsigned int num_rates;
unsigned int i;
+#ifdef CONFIG_OF
+ struct device_node *np = rt2x00dev->dev->of_node;
+ unsigned int enabled;
+ if (!of_property_read_u32(np, "ralink,2ghz",
+ &enabled) && !enabled)
+ spec->supported_bands &= ~SUPPORT_BAND_2GHZ;
+ if (!of_property_read_u32(np, "ralink,5ghz",
+ &enabled) && !enabled)
+ spec->supported_bands &= ~SUPPORT_BAND_5GHZ;
+#endif /* CONFIG_OF */
if (rt2x00dev->dev->platform_data) {
struct rt2x00_platform_data *pdata;

View File

@@ -0,0 +1,33 @@
From 04dbd87265f6ba4a373b211ba324b437d224fb2d Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 17 Mar 2013 00:03:31 +0100
Subject: [PATCH 21/38] rt2x00: make wmac loadable via OF on rt288x/305x SoC
This patch ads the match table to allow loading the wmac support from a
devicetree.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/net/wireless/ralink/rt2x00/rt2800pci.c | 7 +++++++
1 file changed, 7 insertions(+)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -235,10 +235,17 @@ static int rt2800soc_probe(struct platfo
return rt2x00soc_probe(pdev, &rt2800soc_ops);
}
+static const struct of_device_id rt2880_wmac_match[] = {
+ { .compatible = "ralink,rt2880-wmac" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt2880_wmac_match);
+
static struct platform_driver rt2800soc_driver = {
.driver = {
.name = "rt2800_wmac",
.mod_name = KBUILD_MODNAME,
+ .of_match_table = rt2880_wmac_match,
},
.probe = rt2800soc_probe,
.remove = rt2x00soc_remove,

View File

@@ -0,0 +1,40 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -36,6 +36,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include "rt2x00.h"
#include "rt2800lib.h"
@@ -9542,6 +9543,17 @@ static int rt2800_init_eeprom(struct rt2
rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
+ {
+ struct device_node *np = rt2x00dev->dev->of_node;
+ unsigned int led_polarity;
+
+ /* Allow overriding polarity from OF */
+ if (!of_property_read_u32(np, "ralink,led-polarity",
+ &led_polarity))
+ rt2x00_set_field16(&eeprom, EEPROM_FREQ_LED_POLARITY,
+ led_polarity);
+ }
+
rt2x00dev->led_mcu_reg = eeprom;
#endif /* CPTCFG_RT2X00_LIB_LEDS */
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00leds.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00leds.c
@@ -109,6 +109,9 @@ static int rt2x00leds_register_led(struc
led->led_dev.name = name;
led->led_dev.brightness = LED_OFF;
+ if (rt2x00_is_soc(rt2x00dev))
+ led->led_dev.brightness_set(&led->led_dev, LED_OFF);
+
retval = led_classdev_register(device, &led->led_dev);
if (retval) {
rt2x00_err(rt2x00dev, "Failed to register led handler\n");

View File

@@ -0,0 +1,11 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1367,7 +1367,7 @@ static inline void rt2x00lib_set_if_comb
*/
if_limit = &rt2x00dev->if_limits_ap;
if_limit->max = rt2x00dev->ops->max_ap_intf;
- if_limit->types = BIT(NL80211_IFTYPE_AP);
+ if_limit->types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION);
#ifdef CPTCFG_MAC80211_MESH
if_limit->types |= BIT(NL80211_IFTYPE_MESH_POINT);
#endif

View File

@@ -0,0 +1,44 @@
From: David Bauer <mail@david-bauer.net>
Date: Mon, 16 Dec 2019 20:47:06 +0100
Subject: [PATCH] rt2x00: add throughput LED trigger
This adds a (currently missing) throughput LED trigger for the rt2x00
driver. Previously, LED triggers had to be assigned to the netdev, which
was limited to a single VAP.
Signed-off-by: David Bauer <mail@david-bauer.net>
Tested-by: Christoph Krapp <achterin@googlemail.com>
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1140,6 +1140,19 @@ static void rt2x00lib_remove_hw(struct r
kfree(rt2x00dev->spec.channels_info);
}
+static const struct ieee80211_tpt_blink rt2x00_tpt_blink[] = {
+ { .throughput = 0 * 1024, .blink_time = 334 },
+ { .throughput = 1 * 1024, .blink_time = 260 },
+ { .throughput = 2 * 1024, .blink_time = 220 },
+ { .throughput = 5 * 1024, .blink_time = 190 },
+ { .throughput = 10 * 1024, .blink_time = 170 },
+ { .throughput = 25 * 1024, .blink_time = 150 },
+ { .throughput = 54 * 1024, .blink_time = 130 },
+ { .throughput = 120 * 1024, .blink_time = 110 },
+ { .throughput = 265 * 1024, .blink_time = 80 },
+ { .throughput = 586 * 1024, .blink_time = 50 },
+};
+
static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
@@ -1222,6 +1235,10 @@ static int rt2x00lib_probe_hw(struct rt2
#undef RT2X00_TASKLET_INIT
+ ieee80211_create_tpt_led_trigger(rt2x00dev->hw,
+ IEEE80211_TPT_LEDTRIG_FL_RADIO, rt2x00_tpt_blink,
+ ARRAY_SIZE(rt2x00_tpt_blink));
+
/*
* Register HW.
*/

View File

@@ -0,0 +1,107 @@
From 9782a7f7488443568fa4d6088b73c9aff7eb8510 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Wed, 19 Apr 2017 16:14:53 +0200
Subject: [PATCH] rt2x00: add support for external PA on MT7620
To: Stanislaw Gruszka <sgruszka@redhat.com>
Cc: Helmut Schaa <helmut.schaa@googlemail.com>,
linux-wireless@vger.kernel.org,
Kalle Valo <kvalo@codeaurora.org>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
[pozega.tomislav@gmail.com: use chanreg and dccal helpers.]
---
drivers/net/wireless/ralink/rt2x00/rt2800.h | 1 +
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 70 +++++++++++++++++++++++++-
2 files changed, 70 insertions(+), 1 deletion(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
@@ -2750,6 +2750,7 @@ enum rt2800_eeprom_word {
#define EEPROM_NIC_CONF2_RX_STREAM FIELD16(0x000f)
#define EEPROM_NIC_CONF2_TX_STREAM FIELD16(0x00f0)
#define EEPROM_NIC_CONF2_CRYSTAL FIELD16(0x0600)
+#define EEPROM_NIC_CONF2_EXTERNAL_PA FIELD16(0xc000)
/*
* EEPROM LNA
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -4370,6 +4370,45 @@ static void rt2800_config_channel(struct
rt2800_iq_calibrate(rt2x00dev, rf->channel);
}
+ if (rt2x00_rt(rt2x00dev, RT6352)) {
+ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0,
+ &rt2x00dev->cap_flags)) {
+ rt2x00_warn(rt2x00dev, "Using incomplete support for " \
+ "external PA\n");
+ reg = rt2800_register_read(rt2x00dev, RF_CONTROL3);
+ reg |= 0x00000101;
+ rt2800_register_write(rt2x00dev, RF_CONTROL3, reg);
+
+ reg = rt2800_register_read(rt2x00dev, RF_BYPASS3);
+ reg |= 0x00000101;
+ rt2800_register_write(rt2x00dev, RF_BYPASS3, reg);
+
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0x73);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0x73);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0x73);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0xC8);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xA4);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x05);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0xC8);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xA4);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x05);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x27);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0xC8);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xA4);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x05);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 05, 0x00);
+
+ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT,
+ 0x36303636);
+ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN,
+ 0x6C6C6B6C);
+ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN,
+ 0x6C6C6B6C);
+ }
+ }
+
bbp = rt2800_bbp_read(rt2x00dev, 4);
rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf));
rt2800_bbp_write(rt2x00dev, 4, bbp);
@@ -9571,7 +9610,8 @@ static int rt2800_init_eeprom(struct rt2
*/
eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1);
- if (rt2x00_rt(rt2x00dev, RT3352)) {
+ if (rt2x00_rt(rt2x00dev, RT3352) ||
+ rt2x00_rt(rt2x00dev, RT6352)) {
if (rt2x00_get_field16(eeprom,
EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352))
__set_bit(CAPABILITY_EXTERNAL_PA_TX0,
@@ -9582,6 +9622,18 @@ static int rt2800_init_eeprom(struct rt2
&rt2x00dev->cap_flags);
}
+ eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF2);
+
+ if (rt2x00_rt(rt2x00dev, RT6352) && eeprom != 0 && eeprom != 0xffff) {
+ if (rt2x00_get_field16(eeprom,
+ EEPROM_NIC_CONF2_EXTERNAL_PA)) {
+ __set_bit(CAPABILITY_EXTERNAL_PA_TX0,
+ &rt2x00dev->cap_flags);
+ __set_bit(CAPABILITY_EXTERNAL_PA_TX1,
+ &rt2x00dev->cap_flags);
+ }
+ }
+
return 0;
}

View File

@@ -0,0 +1,89 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -8433,6 +8433,58 @@ static void rt2800_init_rfcsr_5592(struc
rt2800_led_open_drain_enable(rt2x00dev);
}
+void rt2800_rf_self_txdc_cal(struct rt2x00_dev *rt2x00dev)
+{
+ u8 rfb5r1_org, rfb7r1_org, rfvalue;
+ u32 mac0518, mac051c, mac0528, mac052c;
+ u8 i;
+
+ rt2x00_info(rt2x00dev, "RF Tx self calibration start\n");
+ mac0518 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
+ mac051c = rt2800_register_read(rt2x00dev, RF_BYPASS0);
+ mac0528 = rt2800_register_read(rt2x00dev, RF_CONTROL2);
+ mac052c = rt2800_register_read(rt2x00dev, RF_BYPASS2);
+
+ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x0);
+ rt2800_register_write(rt2x00dev, RF_BYPASS2, 0x0);
+
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0xC);
+ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x3306);
+ rt2800_register_write(rt2x00dev, RF_CONTROL2, 0x3330);
+ rt2800_register_write(rt2x00dev, RF_BYPASS2, 0xfffff);
+ rfb5r1_org = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1);
+ rfb7r1_org = rt2800_rfcsr_read_bank(rt2x00dev, 7, 1);
+
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 1, 0x4);
+ for (i = 0; i < 100; i = i + 1) {
+ udelay(50);
+ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1);
+ if((rfvalue & 0x04) != 0x4)
+ break;
+ }
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 1, rfb5r1_org);
+
+ rt2800_rfcsr_write_bank(rt2x00dev, 7, 1, 0x4);
+ for (i = 0; i < 100; i = i + 1) {
+ udelay(50);
+ rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 1);
+ if((rfvalue & 0x04) != 0x4)
+ break;
+ }
+ rt2800_rfcsr_write_bank(rt2x00dev, 7, 1, rfb7r1_org);
+
+ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x0);
+ rt2800_register_write(rt2x00dev, RF_BYPASS2, 0x0);
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, mac0518);
+ rt2800_register_write(rt2x00dev, RF_BYPASS0, mac051c);
+ rt2800_register_write(rt2x00dev, RF_CONTROL2, mac0528);
+ rt2800_register_write(rt2x00dev, RF_BYPASS2, mac052c);
+
+ rt2x00_info(rt2x00dev, "RF Tx self calibration end\n");
+
+}
+EXPORT_SYMBOL_GPL(rt2800_rf_self_txdc_cal);
+
static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
bool set_bw, bool is_ht40)
{
@@ -9040,6 +9092,7 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
+ rt2800_rf_self_txdc_cal(rt2x00dev);
rt2800_bw_filter_calibration(rt2x00dev, true);
rt2800_bw_filter_calibration(rt2x00dev, false);
}
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -253,6 +253,7 @@ void rt2800_link_tuner(struct rt2x00_dev
const u32 count);
void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev);
void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev);
+void rt2800_rf_self_txdc_cal(struct rt2x00_dev *rt2x00dev);
int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -574,6 +574,7 @@ struct rt2x00lib_ops {
struct link_qual *qual, const u32 count);
void (*gain_calibration) (struct rt2x00_dev *rt2x00dev);
void (*vco_calibration) (struct rt2x00_dev *rt2x00dev);
+ void (*rf_self_txdc_cal) (struct rt2x00_dev *rt2x00dev);
/*
* Data queue handlers.

View File

@@ -0,0 +1,193 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -8485,6 +8485,160 @@ void rt2800_rf_self_txdc_cal(struct rt2x
}
EXPORT_SYMBOL_GPL(rt2800_rf_self_txdc_cal);
+int rt2800_calcrcalibrationcode(struct rt2x00_dev *rt2x00dev, int d1, int d2)
+{
+ int calcode;
+ calcode = ((d2 - d1) * 1000) / 43;
+ if ((calcode%10) >= 5)
+ calcode += 10;
+ calcode = (calcode / 10);
+
+ return calcode;
+}
+EXPORT_SYMBOL_GPL(rt2800_calcrcalibrationcode);
+
+void rt2800_r_calibration(struct rt2x00_dev *rt2x00dev)
+{
+ u32 savemacsysctrl;
+ u8 saverfb0r1, saverfb0r34, saverfb0r35;
+ u8 saverfb5r4, saverfb5r17, saverfb5r18;
+ u8 saverfb5r19, saverfb5r20;
+ u8 savebbpr22, savebbpr47, savebbpr49;
+ u8 bytevalue = 0;
+ int rcalcode;
+ u8 r_cal_code = 0;
+ char d1 = 0, d2 = 0;
+ u8 rfvalue;
+ u32 MAC_RF_BYPASS0, MAC_RF_CONTROL0, MAC_PWR_PIN_CFG;
+
+ saverfb0r1 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 1);
+ saverfb0r34 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 34);
+ saverfb0r35 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 35);
+ saverfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4);
+ saverfb5r17 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17);
+ saverfb5r18 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 18);
+ saverfb5r19 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 19);
+ saverfb5r20 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 20);
+
+ savebbpr22 = rt2800_bbp_read(rt2x00dev, 22);
+ savebbpr47 = rt2800_bbp_read(rt2x00dev, 47);
+ savebbpr49 = rt2800_bbp_read(rt2x00dev, 49);
+
+ savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ MAC_RF_BYPASS0 = rt2800_register_read(rt2x00dev, RF_BYPASS0);
+ MAC_RF_CONTROL0 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
+ MAC_PWR_PIN_CFG = rt2800_register_read(rt2x00dev, PWR_PIN_CFG);
+
+ {
+ u32 maccfg, macstatus;
+ int i;
+
+ maccfg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ maccfg &= (~0x04);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, maccfg);
+
+ for (i = 0; i < 10000; i++) {
+ macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+ if (macstatus & 0x1)
+ udelay(50);
+ else
+ break;
+ }
+
+ if (i == 10000)
+ rt2x00_warn(rt2x00dev, "Wait MAC Tx Status to MAX !!!\n");
+
+ maccfg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ maccfg &= (~0x04);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, maccfg);
+
+ for (i = 0; i < 10000; i++) {
+ macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+ if (macstatus & 0x2)
+ udelay(50);
+ else
+ break;
+ }
+
+ if (i == 10000)
+ rt2x00_warn(rt2x00dev, "Wait MAC Rx Status to MAX !!!\n");
+ }
+
+ rfvalue = (MAC_RF_BYPASS0 | 0x3004);
+ rt2800_register_write(rt2x00dev, RF_BYPASS0, rfvalue);
+ rfvalue = (MAC_RF_CONTROL0 | (~0x3002));
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, rfvalue);
+
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, 0x27);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, 0x80);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, 0x83);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, 0x00);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, 0x20);
+
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, 0x00);
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 34, 0x13);
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x00);
+
+ rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x1);
+
+ rt2800_bbp_write(rt2x00dev, 47, 0x04);
+ rt2800_bbp_write(rt2x00dev, 22, 0x80);
+ udelay(100);
+ bytevalue = rt2800_bbp_read(rt2x00dev, 49);
+ if (bytevalue > 128)
+ d1 = bytevalue - 256;
+ else
+ d1 = (char)bytevalue;
+ rt2800_bbp_write(rt2x00dev, 22, 0x0);
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x01);
+
+ rt2800_bbp_write(rt2x00dev, 22, 0x80);
+ udelay(100);
+ bytevalue = rt2800_bbp_read(rt2x00dev, 49);
+ if (bytevalue > 128)
+ d2 = bytevalue - 256;
+ else
+ d2 = (char)bytevalue;
+ rt2800_bbp_write(rt2x00dev, 22, 0x0);
+
+ rcalcode = rt2800_calcrcalibrationcode(rt2x00dev, d1, d2);
+ if (rcalcode < 0)
+ r_cal_code = 256 + rcalcode;
+ else
+ r_cal_code = (u8)rcalcode;
+
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 7, r_cal_code);
+
+ rt2800_bbp_write(rt2x00dev, 22, 0x0);
+
+ bytevalue = rt2800_bbp_read(rt2x00dev, 21);
+ bytevalue |= 0x1;
+ rt2800_bbp_write(rt2x00dev, 21, bytevalue);
+ bytevalue = rt2800_bbp_read(rt2x00dev, 21);
+ bytevalue &= (~0x1);
+ rt2800_bbp_write(rt2x00dev, 21, bytevalue);
+
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, saverfb0r1);
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 34, saverfb0r34);
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, saverfb0r35);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, saverfb5r4);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, saverfb5r17);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, saverfb5r18);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, saverfb5r19);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, saverfb5r20);
+
+ rt2800_bbp_write(rt2x00dev, 22, savebbpr22);
+ rt2800_bbp_write(rt2x00dev, 47, savebbpr47);
+ rt2800_bbp_write(rt2x00dev, 49, savebbpr49);
+
+ rt2800_register_write(rt2x00dev, RF_BYPASS0, MAC_RF_BYPASS0);
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, MAC_RF_CONTROL0);
+
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl);
+ rt2800_register_write(rt2x00dev, PWR_PIN_CFG, MAC_PWR_PIN_CFG);
+}
+EXPORT_SYMBOL_GPL(rt2800_r_calibration);
+
static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
bool set_bw, bool is_ht40)
{
@@ -9092,6 +9246,7 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
+ rt2800_r_calibration(rt2x00dev);
rt2800_rf_self_txdc_cal(rt2x00dev);
rt2800_bw_filter_calibration(rt2x00dev, true);
rt2800_bw_filter_calibration(rt2x00dev, false);
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -254,6 +254,8 @@ void rt2800_link_tuner(struct rt2x00_dev
void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev);
void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev);
void rt2800_rf_self_txdc_cal(struct rt2x00_dev *rt2x00dev);
+int rt2800_calcrcalibrationcode(struct rt2x00_dev *rt2x00dev, int d1, int d2);
+void rt2800_r_calibration(struct rt2x00_dev *rt2x00dev);
int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -575,6 +575,8 @@ struct rt2x00lib_ops {
void (*gain_calibration) (struct rt2x00_dev *rt2x00dev);
void (*vco_calibration) (struct rt2x00_dev *rt2x00dev);
void (*rf_self_txdc_cal) (struct rt2x00_dev *rt2x00dev);
+ int (*calcrcalibrationcode) (struct rt2x00_dev *rt2x00dev, int d1, int d2);
+ void (*r_calibration) (struct rt2x00_dev *rt2x00dev);
/*
* Data queue handlers.

View File

@@ -0,0 +1,102 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -8639,6 +8639,71 @@ void rt2800_r_calibration(struct rt2x00_
}
EXPORT_SYMBOL_GPL(rt2800_r_calibration);
+void rt2800_rxdcoc_calibration(struct rt2x00_dev *rt2x00dev)
+{
+ u8 bbpreg = 0;
+ u32 macvalue = 0, macvalue1 = 0;
+ u8 saverfb0r2, saverfb5r4, saverfb7r4, rfvalue;
+ int i;
+
+ saverfb0r2 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 2);
+ rfvalue = saverfb0r2;
+ rfvalue |= 0x03;
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfvalue);
+
+ rt2800_bbp_write(rt2x00dev, 158, 141);
+ bbpreg = rt2800_bbp_read(rt2x00dev, 159);
+ bbpreg |= 0x10;
+ rt2800_bbp_write(rt2x00dev, 159, bbpreg);
+
+ macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x8);
+
+ for (i = 0; i < 10000; i++) {
+ macvalue1 = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+ if (macvalue1 & 0x1)
+ udelay(50);
+ else
+ break;
+ }
+
+ saverfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0);
+ saverfb7r4 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 4);
+ saverfb5r4 = saverfb5r4 & (~0x40);
+ saverfb7r4 = saverfb7r4 & (~0x40);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x64);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, saverfb5r4);
+ rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, saverfb7r4);
+
+ rt2800_bbp_write(rt2x00dev, 158, 141);
+ bbpreg = rt2800_bbp_read(rt2x00dev, 159);
+ bbpreg = bbpreg & (~0x40);
+ rt2800_bbp_write(rt2x00dev, 159, bbpreg);
+ bbpreg |= 0x48;
+ rt2800_bbp_write(rt2x00dev, 159, bbpreg);
+
+ for (i = 0; i < 10000; i++) {
+ bbpreg = rt2800_bbp_read(rt2x00dev, 159);
+ if ((bbpreg & 0x40)==0)
+ break;
+ udelay(50);
+ }
+
+ bbpreg = rt2800_bbp_read(rt2x00dev, 159);
+ bbpreg = bbpreg & (~0x40);
+ rt2800_bbp_write(rt2x00dev, 159, bbpreg);
+
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue);
+
+ rt2800_bbp_write(rt2x00dev, 158, 141);
+ bbpreg = rt2800_bbp_read(rt2x00dev, 159);
+ bbpreg &= (~0x10);
+ rt2800_bbp_write(rt2x00dev, 159, bbpreg);
+
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, saverfb0r2);
+}
+EXPORT_SYMBOL_GPL(rt2800_rxdcoc_calibration);
+
static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
bool set_bw, bool is_ht40)
{
@@ -9248,6 +9313,7 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_r_calibration(rt2x00dev);
rt2800_rf_self_txdc_cal(rt2x00dev);
+ rt2800_rxdcoc_calibration(rt2x00dev);
rt2800_bw_filter_calibration(rt2x00dev, true);
rt2800_bw_filter_calibration(rt2x00dev, false);
}
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -256,6 +256,7 @@ void rt2800_vco_calibration(struct rt2x0
void rt2800_rf_self_txdc_cal(struct rt2x00_dev *rt2x00dev);
int rt2800_calcrcalibrationcode(struct rt2x00_dev *rt2x00dev, int d1, int d2);
void rt2800_r_calibration(struct rt2x00_dev *rt2x00dev);
+void rt2800_rxdcoc_calibration(struct rt2x00_dev *rt2x00dev);
int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -577,6 +577,7 @@ struct rt2x00lib_ops {
void (*rf_self_txdc_cal) (struct rt2x00_dev *rt2x00dev);
int (*calcrcalibrationcode) (struct rt2x00_dev *rt2x00dev, int d1, int d2);
void (*r_calibration) (struct rt2x00_dev *rt2x00dev);
+ void (*rxdcoc_calibration) (struct rt2x00_dev *rt2x00dev);
/*
* Data queue handlers.

View File

@@ -0,0 +1,417 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -8704,6 +8704,386 @@ void rt2800_rxdcoc_calibration(struct rt
}
EXPORT_SYMBOL_GPL(rt2800_rxdcoc_calibration);
+static u32 rt2800_do_sqrt_accumulation(u32 si) {
+ u32 root, root_pre, bit;
+ char i;
+ bit = 1 << 15;
+ root = 0;
+ for (i = 15; i >= 0; i = i - 1) {
+ root_pre = root + bit;
+ if ((root_pre*root_pre) <= si)
+ root = root_pre;
+ bit = bit >> 1;
+ }
+
+ return root;
+}
+EXPORT_SYMBOL_GPL(rt2800_do_sqrt_accumulation);
+
+void rt2800_rxiq_calibration(struct rt2x00_dev *rt2x00dev) {
+ u8 rfb0r1, rfb0r2, rfb0r42;
+ u8 rfb4r0, rfb4r19;
+ u8 rfb5r3, rfb5r4, rfb5r17, rfb5r18, rfb5r19, rfb5r20;
+ u8 rfb6r0, rfb6r19;
+ u8 rfb7r3, rfb7r4, rfb7r17, rfb7r18, rfb7r19, rfb7r20;
+
+ u8 bbp1, bbp4;
+ u8 bbpr241, bbpr242;
+ u32 i;
+ u8 ch_idx;
+ u8 bbpval;
+ u8 rfval, vga_idx = 0;
+ int mi = 0, mq = 0, si = 0, sq = 0, riq = 0;
+ int sigma_i, sigma_q, r_iq, g_rx;
+ int g_imb;
+ int ph_rx;
+ u32 savemacsysctrl = 0;
+ u32 orig_RF_CONTROL0 = 0;
+ u32 orig_RF_BYPASS0 = 0;
+ u32 orig_RF_CONTROL1 = 0;
+ u32 orig_RF_BYPASS1 = 0;
+ u32 orig_RF_CONTROL3 = 0;
+ u32 orig_RF_BYPASS3 = 0;
+ u32 macstatus, bbpval1 = 0;
+ u8 rf_vga_table[] = {0x20, 0x21, 0x22, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f};
+
+ savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ orig_RF_CONTROL0 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
+ orig_RF_BYPASS0 = rt2800_register_read(rt2x00dev, RF_BYPASS0);
+ orig_RF_CONTROL1 = rt2800_register_read(rt2x00dev, RF_CONTROL1);
+ orig_RF_BYPASS1 = rt2800_register_read(rt2x00dev, RF_BYPASS1);
+ orig_RF_CONTROL3 = rt2800_register_read(rt2x00dev, RF_CONTROL3);
+ orig_RF_BYPASS3 = rt2800_register_read(rt2x00dev, RF_BYPASS3);
+
+ bbp1 = rt2800_bbp_read(rt2x00dev, 1);
+ bbp4 = rt2800_bbp_read(rt2x00dev, 4);
+
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x0);
+
+ for (i = 0; i < 10000; i++) {
+ macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+ if (macstatus & 0x3)
+ udelay(50);
+ else
+ break;
+ }
+
+ if (i == 10000)
+ rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n");
+
+ bbpval = bbp4 & (~0x18);
+ bbpval = bbp4 | 0x00;
+ rt2800_bbp_write(rt2x00dev, 4, bbpval);
+
+ bbpval = rt2800_bbp_read(rt2x00dev, 21);
+ bbpval = bbpval | 1;
+ rt2800_bbp_write(rt2x00dev, 21, bbpval);
+ bbpval = bbpval & 0xfe;
+ rt2800_bbp_write(rt2x00dev, 21, bbpval);
+
+ rt2800_register_write(rt2x00dev, RF_CONTROL1, 0x00000202);
+ rt2800_register_write(rt2x00dev, RF_BYPASS1, 0x00000303);
+ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
+ rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x0101);
+ } else {
+ rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x0000);
+ }
+ rt2800_register_write(rt2x00dev, RF_BYPASS3, 0xf1f1);
+
+ rfb0r1 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 1);
+ rfb0r2 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 2);
+ rfb0r42 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 42);
+ rfb4r0 = rt2800_rfcsr_read_bank(rt2x00dev, 4, 0);
+ rfb4r19 = rt2800_rfcsr_read_bank(rt2x00dev, 4, 19);
+ rfb5r3 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 3);
+ rfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4);
+ rfb5r17 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17);
+ rfb5r18 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 18);
+ rfb5r19 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 19);
+ rfb5r20 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 20);
+
+ rfb6r0 = rt2800_rfcsr_read_bank(rt2x00dev, 6, 0);
+ rfb6r19 = rt2800_rfcsr_read_bank(rt2x00dev, 6, 19);
+ rfb7r3 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 3);
+ rfb7r4 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 4);
+ rfb7r17 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 17);
+ rfb7r18 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 18);
+ rfb7r19 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 19);
+ rfb7r20 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 20);
+
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x87);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0x27);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x38);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x38);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x80);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 18, 0xC1);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 19, 0x60);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 20, 0x00);
+
+ rt2800_bbp_write(rt2x00dev, 23, 0x0);
+ rt2800_bbp_write(rt2x00dev, 24, 0x0);
+
+ rt2800_bbp_dcoc_write(rt2x00dev, 5, 0x0);
+
+ bbpr241 = rt2800_bbp_read(rt2x00dev, 241);
+ bbpr242 = rt2800_bbp_read(rt2x00dev, 242);
+
+ rt2800_bbp_write(rt2x00dev, 241, 0x10);
+ rt2800_bbp_write(rt2x00dev, 242, 0x84);
+ rt2800_bbp_write(rt2x00dev, 244, 0x31);
+
+ bbpval = rt2800_bbp_dcoc_read(rt2x00dev, 3);
+ bbpval = bbpval & (~0x7);
+ rt2800_bbp_dcoc_write(rt2x00dev, 3, bbpval);
+
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000004);
+ udelay(1);
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000006);
+ usleep_range(1, 200);
+ rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x00003376);
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001006);
+ udelay(1);
+ if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
+ rt2800_bbp_write(rt2x00dev, 23, 0x06);
+ rt2800_bbp_write(rt2x00dev, 24, 0x06);
+ } else {
+ rt2800_bbp_write(rt2x00dev, 23, 0x02);
+ rt2800_bbp_write(rt2x00dev, 24, 0x02);
+ }
+
+ for (ch_idx = 0; ch_idx < 2; ch_idx = ch_idx + 1) {
+ if (ch_idx == 0) {
+ rfval = rfb0r1 & (~0x3);
+ rfval = rfb0r1 | 0x1;
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, rfval);
+ rfval = rfb0r2 & (~0x33);
+ rfval = rfb0r2 | 0x11;
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfval);
+ rfval = rfb0r42 & (~0x50);
+ rfval = rfb0r42 | 0x10;
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfval);
+
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001006);
+ udelay(1);
+
+ bbpval = bbp1 & (~ 0x18);
+ bbpval = bbpval | 0x00;
+ rt2800_bbp_write(rt2x00dev, 1, bbpval);
+
+ rt2800_bbp_dcoc_write(rt2x00dev, 1, 0x00);
+ } else {
+ rfval = rfb0r1 & (~0x3);
+ rfval = rfb0r1 | 0x2;
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, rfval);
+ rfval = rfb0r2 & (~0x33);
+ rfval = rfb0r2 | 0x22;
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfval);
+ rfval = rfb0r42 & (~0x50);
+ rfval = rfb0r42 | 0x40;
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfval);
+
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00002006);
+ udelay(1);
+
+ bbpval = bbp1 & (~ 0x18);
+ bbpval = bbpval | 0x08;
+ rt2800_bbp_write(rt2x00dev, 1, bbpval);
+
+ rt2800_bbp_dcoc_write(rt2x00dev, 1, 0x01);
+ }
+ udelay(500);
+
+ vga_idx = 0;
+ while (vga_idx < 11) {
+ rt2800_rfcsr_write_dccal(rt2x00dev, 3, rf_vga_table[vga_idx]);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 4, rf_vga_table[vga_idx]);
+
+ rt2800_bbp_dcoc_write(rt2x00dev, 0, 0x93);
+
+ for (i = 0; i < 10000; i++) {
+ bbpval = rt2800_bbp_read(rt2x00dev, 159);
+ if ((bbpval & 0xff) == 0x93)
+ udelay(50);
+ else
+ break;
+ }
+
+ if ((bbpval & 0xff) == 0x93) {
+ rt2x00_warn(rt2x00dev, "Fatal Error: Calibration doesn't finish");
+ goto restore_value;
+ }
+
+ for (i = 0; i < 5; i++) {
+ u32 bbptemp = 0;
+ u8 value = 0;
+ int result = 0;
+
+ rt2800_bbp_write(rt2x00dev, 158, 0x1e);
+ rt2800_bbp_write(rt2x00dev, 159, i);
+ rt2800_bbp_write(rt2x00dev, 158, 0x22);
+ value = rt2800_bbp_read(rt2x00dev, 159);
+ bbptemp = bbptemp + (value << 24);
+ rt2800_bbp_write(rt2x00dev, 158, 0x21);
+ value = rt2800_bbp_read(rt2x00dev, 159);
+ bbptemp = bbptemp + (value << 16);
+ rt2800_bbp_write(rt2x00dev, 158, 0x20);
+ value = rt2800_bbp_read(rt2x00dev, 159);
+ bbptemp = bbptemp + (value << 8);
+ rt2800_bbp_write(rt2x00dev, 158, 0x1f);
+ value = rt2800_bbp_read(rt2x00dev, 159);
+ bbptemp = bbptemp + value;
+
+ if ((i < 2) && (bbptemp & 0x800000))
+ result = (bbptemp & 0xffffff) - 0x1000000;
+ else if (i == 4)
+ result = bbptemp;
+ else
+ result = bbptemp;
+
+ if (i == 0)
+ mi = result/4096;
+ else if (i == 1)
+ mq = result/4096;
+ else if (i == 2)
+ si = bbptemp/4096;
+ else if (i == 3)
+ sq = bbptemp/4096;
+ else
+ riq = result/4096;
+ }
+
+ bbpval1 = si - mi*mi;
+ rt2x00_dbg(rt2x00dev, "RXIQ si=%d, sq=%d, riq=%d, bbpval %d, vga_idx %d", si, sq, riq, bbpval1, vga_idx);
+
+ if (bbpval1 >= (100*100))
+ break;
+
+ if (bbpval1 <= 100)
+ vga_idx = vga_idx + 9;
+ else if (bbpval1 <= 158)
+ vga_idx = vga_idx + 8;
+ else if (bbpval1 <= 251)
+ vga_idx = vga_idx + 7;
+ else if (bbpval1 <= 398)
+ vga_idx = vga_idx + 6;
+ else if (bbpval1 <= 630)
+ vga_idx = vga_idx + 5;
+ else if (bbpval1 <= 1000)
+ vga_idx = vga_idx + 4;
+ else if (bbpval1 <= 1584)
+ vga_idx = vga_idx + 3;
+ else if (bbpval1 <= 2511)
+ vga_idx = vga_idx + 2;
+ else
+ vga_idx = vga_idx + 1;
+ }
+
+ sigma_i = rt2800_do_sqrt_accumulation(100*(si - mi*mi));
+ sigma_q = rt2800_do_sqrt_accumulation(100*(sq - mq*mq));
+ r_iq = 10*(riq-(mi*mq));
+
+ rt2x00_dbg(rt2x00dev, "Sigma_i=%d, Sigma_q=%d, R_iq=%d", sigma_i, sigma_q, r_iq);
+
+ if (((sigma_i <= 1400 ) && (sigma_i >= 1000))
+ && ((sigma_i - sigma_q) <= 112)
+ && ((sigma_i - sigma_q) >= -112)
+ && ((mi <= 32) && (mi >= -32))
+ && ((mq <= 32) && (mq >= -32))) {
+ r_iq = 10*(riq-(mi*mq));
+ rt2x00_dbg(rt2x00dev, "RXIQ Sigma_i=%d, Sigma_q=%d, R_iq=%d\n", sigma_i, sigma_q, r_iq);
+
+ g_rx = (1000 * sigma_q) / sigma_i;
+ g_imb = ((-2) * 128 * (1000 - g_rx)) / (1000 + g_rx);
+ ph_rx = (r_iq * 2292) / (sigma_i * sigma_q);
+ rt2x00_info(rt2x00dev, "RXIQ G_imb=%d, Ph_rx=%d\n", g_imb, ph_rx);
+
+ if ((ph_rx > 20) || (ph_rx < -20)) {
+ ph_rx = 0;
+ rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
+ }
+
+ if ((g_imb > 12) || (g_imb < -12)) {
+ g_imb = 0;
+ rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
+ }
+ }
+ else {
+ g_imb = 0;
+ ph_rx = 0;
+ rt2x00_dbg(rt2x00dev, "RXIQ Sigma_i=%d, Sigma_q=%d, R_iq=%d\n", sigma_i, sigma_q, r_iq);
+ rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
+ }
+
+ if (ch_idx == 0) {
+ rt2800_bbp_write(rt2x00dev, 158, 0x37);
+ rt2800_bbp_write(rt2x00dev, 159, g_imb & 0x3f);
+ rt2800_bbp_write(rt2x00dev, 158, 0x35);
+ rt2800_bbp_write(rt2x00dev, 159, ph_rx & 0x3f);
+ } else {
+ rt2800_bbp_write(rt2x00dev, 158, 0x55);
+ rt2800_bbp_write(rt2x00dev, 159, g_imb & 0x3f);
+ rt2800_bbp_write(rt2x00dev, 158, 0x53);
+ rt2800_bbp_write(rt2x00dev, 159, ph_rx & 0x3f);
+ }
+ }
+
+restore_value:
+ rt2800_bbp_write(rt2x00dev, 158, 0x3);
+ bbpval = rt2800_bbp_read(rt2x00dev, 159);
+ rt2800_bbp_write(rt2x00dev, 159, (bbpval | 0x07));
+
+ rt2800_bbp_write(rt2x00dev, 158, 0x00);
+ rt2800_bbp_write(rt2x00dev, 159, 0x00);
+ rt2800_bbp_write(rt2x00dev, 1, bbp1);
+ rt2800_bbp_write(rt2x00dev, 4, bbp4);
+ rt2800_bbp_write(rt2x00dev, 241, bbpr241);
+ rt2800_bbp_write(rt2x00dev, 242, bbpr242);
+
+ rt2800_bbp_write(rt2x00dev, 244, 0x00);
+ bbpval = rt2800_bbp_read(rt2x00dev, 21);
+ bbpval = (bbpval | 0x1);
+ rt2800_bbp_write(rt2x00dev, 21, bbpval);
+ usleep_range(10, 200);
+ bbpval = (bbpval & 0xfe);
+ rt2800_bbp_write(rt2x00dev, 21, bbpval);
+
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, rfb0r1);
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfb0r2);
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfb0r42);
+
+ rt2800_rfcsr_write_bank(rt2x00dev, 4, 0, rfb4r0);
+ rt2800_rfcsr_write_bank(rt2x00dev, 4, 19, rfb4r19);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 3, rfb5r3);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, rfb5r4);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, rfb5r17);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, rfb5r18);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, rfb5r19);
+ rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, rfb5r20);
+
+ rt2800_rfcsr_write_bank(rt2x00dev, 6, 0, rfb6r0);
+ rt2800_rfcsr_write_bank(rt2x00dev, 6, 19, rfb6r19);
+ rt2800_rfcsr_write_bank(rt2x00dev, 7, 3, rfb7r3);
+ rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, rfb7r4);
+ rt2800_rfcsr_write_bank(rt2x00dev, 7, 17, rfb7r17);
+ rt2800_rfcsr_write_bank(rt2x00dev, 7, 18, rfb7r18);
+ rt2800_rfcsr_write_bank(rt2x00dev, 7, 19, rfb7r19);
+ rt2800_rfcsr_write_bank(rt2x00dev, 7, 20, rfb7r20);
+
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000006);
+ udelay(1);
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000004);
+ udelay(1);
+ rt2800_register_write(rt2x00dev, RF_CONTROL0, orig_RF_CONTROL0);
+ udelay(1);
+ rt2800_register_write(rt2x00dev, RF_BYPASS0, orig_RF_BYPASS0);
+ rt2800_register_write(rt2x00dev, RF_CONTROL1, orig_RF_CONTROL1);
+ rt2800_register_write(rt2x00dev, RF_BYPASS1, orig_RF_BYPASS1);
+ rt2800_register_write(rt2x00dev, RF_CONTROL3, orig_RF_CONTROL3);
+ rt2800_register_write(rt2x00dev, RF_BYPASS3, orig_RF_BYPASS3);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl);
+}
+EXPORT_SYMBOL_GPL(rt2800_rxiq_calibration);
+
static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
bool set_bw, bool is_ht40)
{
@@ -9316,6 +9696,7 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rxdcoc_calibration(rt2x00dev);
rt2800_bw_filter_calibration(rt2x00dev, true);
rt2800_bw_filter_calibration(rt2x00dev, false);
+ rt2800_rxiq_calibration(rt2x00dev);
}
static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -257,6 +257,7 @@ void rt2800_rf_self_txdc_cal(struct rt2x
int rt2800_calcrcalibrationcode(struct rt2x00_dev *rt2x00dev, int d1, int d2);
void rt2800_r_calibration(struct rt2x00_dev *rt2x00dev);
void rt2800_rxdcoc_calibration(struct rt2x00_dev *rt2x00dev);
+void rt2800_rxiq_calibration(struct rt2x00_dev *rt2x00dev);
int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -578,6 +578,7 @@ struct rt2x00lib_ops {
int (*calcrcalibrationcode) (struct rt2x00_dev *rt2x00dev, int d1, int d2);
void (*r_calibration) (struct rt2x00_dev *rt2x00dev);
void (*rxdcoc_calibration) (struct rt2x00_dev *rt2x00dev);
+ void (*rxiq_calibration) (struct rt2x00_dev *rt2x00dev);
/*
* Data queue handlers.

File diff suppressed because it is too large Load Diff