123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- From 5e67d4f8a46d19748b501c2ef86de3f50d3cfd51 Mon Sep 17 00:00:00 2001
- From: Gabor Juhos <juhosg@openwrt.org>
- Date: Sun, 24 Mar 2013 19:26:27 +0100
- Subject: [PATCH] rt2x00: rt2800mmio: add a workaround for spurious
- TX_FIFO_STATUS interrupts
- Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
- ---
- drivers/net/wireless/ralink/rt2x00/rt2800mmio.c | 72 +++++++++++++++++++++++++-----
- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 5 +++
- 2 files changed, 65 insertions(+), 12 deletions(-)
- --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
- @@ -415,9 +415,9 @@ void rt2800mmio_autowake_tasklet(unsigne
- }
- EXPORT_SYMBOL_GPL(rt2800mmio_autowake_tasklet);
-
- -static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
- +static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev,
- + u32 status)
- {
- - u32 status;
- int i;
-
- /*
- @@ -438,29 +438,77 @@ static void rt2800mmio_txstatus_interrup
- * Since we have only one producer and one consumer we don't
- * need to lock the kfifo.
- */
- - for (i = 0; i < rt2x00dev->tx->limit; i++) {
- - rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &status);
- -
- - if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
- - break;
- -
- + i = 0;
- + do {
- if (!kfifo_put(&rt2x00dev->txstatus_fifo, status)) {
- - rt2x00_warn(rt2x00dev, "TX status FIFO overrun, drop tx status report\n");
- + rt2x00_warn(rt2x00dev,
- + "TX status FIFO overrun, drop TX status report\n");
- break;
- }
- - }
- +
- + if (++i >= rt2x00dev->tx->limit)
- + break;
- +
- + rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &status);
- + } while (rt2x00_get_field32(status, TX_STA_FIFO_VALID));
-
- /* Schedule the tasklet for processing the tx status. */
- tasklet_schedule(&rt2x00dev->txstatus_tasklet);
- }
-
- +#define RT2800MMIO_TXSTATUS_IRQ_MAX_RETRIES 4
- +
- +static bool rt2800mmio_txstatus_is_spurious(struct rt2x00_dev *rt2x00dev,
- + u32 txstatus)
- +{
- + if (likely(rt2x00_get_field32(txstatus, TX_STA_FIFO_VALID))) {
- + rt2x00dev->txstatus_irq_retries = 0;
- + return false;
- + }
- +
- + rt2x00dev->txstatus_irq_retries++;
- +
- + /* Ensure that we don't go into an infinite IRQ loop. */
- + if (rt2x00dev->txstatus_irq_retries >=
- + RT2800MMIO_TXSTATUS_IRQ_MAX_RETRIES) {
- + rt2x00_warn(rt2x00dev,
- + "%u spurious TX_FIFO_STATUS interrupt(s)\n",
- + rt2x00dev->txstatus_irq_retries);
- + rt2x00dev->txstatus_irq_retries = 0;
- + return false;
- + }
- +
- + return true;
- +}
- +
- irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance)
- {
- struct rt2x00_dev *rt2x00dev = dev_instance;
- u32 reg, mask;
- + u32 txstatus = 0;
-
- - /* Read status and ACK all interrupts */
- + /* Read status */
- rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, ®);
- +
- + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
- + /* Due to unknown reason the hardware generates a
- + * TX_FIFO_STATUS interrupt before the TX_STA_FIFO
- + * register contain valid data. Read the TX status
- + * here to see if we have to process the actual
- + * request.
- + */
- + rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &txstatus);
- + if (rt2800mmio_txstatus_is_spurious(rt2x00dev, txstatus)) {
- + /* Remove the TX_FIFO_STATUS bit so it won't be
- + * processed in this turn. The hardware will
- + * generate another IRQ for us.
- + */
- + rt2x00_set_field32(®,
- + INT_SOURCE_CSR_TX_FIFO_STATUS, 0);
- + }
- + }
- +
- + /* ACK interrupts */
- rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
-
- if (!reg)
- @@ -477,7 +525,7 @@ irqreturn_t rt2800mmio_interrupt(int irq
- mask = ~reg;
-
- if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
- - rt2800mmio_txstatus_interrupt(rt2x00dev);
- + rt2800mmio_txstatus_interrupt(rt2x00dev, txstatus);
- /*
- * Never disable the TX_FIFO_STATUS interrupt.
- */
- --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
- @@ -991,6 +991,11 @@ struct rt2x00_dev {
- int rf_channel;
-
- /*
- + * Counter for tx status irq retries (rt2800pci).
- + */
- + unsigned int txstatus_irq_retries;
- +
- + /*
- * Protect the interrupt mask register.
- */
- spinlock_t irqmask_lock;
|