600-23-rt2x00-rt2800mmio-add-a-workaround-for-spurious-TX_F.patch 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. From 5e67d4f8a46d19748b501c2ef86de3f50d3cfd51 Mon Sep 17 00:00:00 2001
  2. From: Gabor Juhos <juhosg@openwrt.org>
  3. Date: Sun, 24 Mar 2013 19:26:27 +0100
  4. Subject: [PATCH] rt2x00: rt2800mmio: add a workaround for spurious
  5. TX_FIFO_STATUS interrupts
  6. Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
  7. ---
  8. drivers/net/wireless/ralink/rt2x00/rt2800mmio.c | 72 +++++++++++++++++++++++++-----
  9. drivers/net/wireless/ralink/rt2x00/rt2x00.h | 5 +++
  10. 2 files changed, 65 insertions(+), 12 deletions(-)
  11. --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
  12. +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
  13. @@ -415,9 +415,9 @@ void rt2800mmio_autowake_tasklet(unsigne
  14. }
  15. EXPORT_SYMBOL_GPL(rt2800mmio_autowake_tasklet);
  16. -static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
  17. +static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev,
  18. + u32 status)
  19. {
  20. - u32 status;
  21. int i;
  22. /*
  23. @@ -438,29 +438,77 @@ static void rt2800mmio_txstatus_interrup
  24. * Since we have only one producer and one consumer we don't
  25. * need to lock the kfifo.
  26. */
  27. - for (i = 0; i < rt2x00dev->tx->limit; i++) {
  28. - rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &status);
  29. -
  30. - if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
  31. - break;
  32. -
  33. + i = 0;
  34. + do {
  35. if (!kfifo_put(&rt2x00dev->txstatus_fifo, status)) {
  36. - rt2x00_warn(rt2x00dev, "TX status FIFO overrun, drop tx status report\n");
  37. + rt2x00_warn(rt2x00dev,
  38. + "TX status FIFO overrun, drop TX status report\n");
  39. break;
  40. }
  41. - }
  42. +
  43. + if (++i >= rt2x00dev->tx->limit)
  44. + break;
  45. +
  46. + rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &status);
  47. + } while (rt2x00_get_field32(status, TX_STA_FIFO_VALID));
  48. /* Schedule the tasklet for processing the tx status. */
  49. tasklet_schedule(&rt2x00dev->txstatus_tasklet);
  50. }
  51. +#define RT2800MMIO_TXSTATUS_IRQ_MAX_RETRIES 4
  52. +
  53. +static bool rt2800mmio_txstatus_is_spurious(struct rt2x00_dev *rt2x00dev,
  54. + u32 txstatus)
  55. +{
  56. + if (likely(rt2x00_get_field32(txstatus, TX_STA_FIFO_VALID))) {
  57. + rt2x00dev->txstatus_irq_retries = 0;
  58. + return false;
  59. + }
  60. +
  61. + rt2x00dev->txstatus_irq_retries++;
  62. +
  63. + /* Ensure that we don't go into an infinite IRQ loop. */
  64. + if (rt2x00dev->txstatus_irq_retries >=
  65. + RT2800MMIO_TXSTATUS_IRQ_MAX_RETRIES) {
  66. + rt2x00_warn(rt2x00dev,
  67. + "%u spurious TX_FIFO_STATUS interrupt(s)\n",
  68. + rt2x00dev->txstatus_irq_retries);
  69. + rt2x00dev->txstatus_irq_retries = 0;
  70. + return false;
  71. + }
  72. +
  73. + return true;
  74. +}
  75. +
  76. irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance)
  77. {
  78. struct rt2x00_dev *rt2x00dev = dev_instance;
  79. u32 reg, mask;
  80. + u32 txstatus = 0;
  81. - /* Read status and ACK all interrupts */
  82. + /* Read status */
  83. rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
  84. +
  85. + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
  86. + /* Due to unknown reason the hardware generates a
  87. + * TX_FIFO_STATUS interrupt before the TX_STA_FIFO
  88. + * register contain valid data. Read the TX status
  89. + * here to see if we have to process the actual
  90. + * request.
  91. + */
  92. + rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &txstatus);
  93. + if (rt2800mmio_txstatus_is_spurious(rt2x00dev, txstatus)) {
  94. + /* Remove the TX_FIFO_STATUS bit so it won't be
  95. + * processed in this turn. The hardware will
  96. + * generate another IRQ for us.
  97. + */
  98. + rt2x00_set_field32(&reg,
  99. + INT_SOURCE_CSR_TX_FIFO_STATUS, 0);
  100. + }
  101. + }
  102. +
  103. + /* ACK interrupts */
  104. rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
  105. if (!reg)
  106. @@ -477,7 +525,7 @@ irqreturn_t rt2800mmio_interrupt(int irq
  107. mask = ~reg;
  108. if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
  109. - rt2800mmio_txstatus_interrupt(rt2x00dev);
  110. + rt2800mmio_txstatus_interrupt(rt2x00dev, txstatus);
  111. /*
  112. * Never disable the TX_FIFO_STATUS interrupt.
  113. */
  114. --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
  115. +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
  116. @@ -999,6 +999,11 @@ struct rt2x00_dev {
  117. int rf_channel;
  118. /*
  119. + * Counter for tx status irq retries (rt2800pci).
  120. + */
  121. + unsigned int txstatus_irq_retries;
  122. +
  123. + /*
  124. * Protect the interrupt mask register.
  125. */
  126. spinlock_t irqmask_lock;