aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c41
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c5
4 files changed, 51 insertions, 2 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 69004b968122..20059727ef80 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -98,6 +98,22 @@ static void rt2800usb_stop_queue(struct data_queue *queue)
98 } 98 }
99} 99}
100 100
101/*
102 * test if there is an entry in any TX queue for which DMA is done
103 * but the TX status has not been returned yet
104 */
105static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev)
106{
107 struct data_queue *queue;
108
109 tx_queue_for_each(rt2x00dev, queue) {
110 if (rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE) !=
111 rt2x00queue_get_entry(queue, Q_INDEX_DONE))
112 return true;
113 }
114 return false;
115}
116
101static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, 117static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
102 int urb_status, u32 tx_status) 118 int urb_status, u32 tx_status)
103{ 119{
@@ -115,8 +131,11 @@ static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
115 } else 131 } else
116 rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, 132 rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO,
117 rt2800usb_tx_sta_fifo_read_completed); 133 rt2800usb_tx_sta_fifo_read_completed);
118 } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) 134 } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) {
119 queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); 135 queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
136 } else if (rt2800usb_txstatus_pending(rt2x00dev)) {
137 mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20));
138 }
120} 139}
121 140
122static void rt2800usb_tx_dma_done(struct queue_entry *entry) 141static void rt2800usb_tx_dma_done(struct queue_entry *entry)
@@ -127,6 +146,14 @@ static void rt2800usb_tx_dma_done(struct queue_entry *entry)
127 rt2800usb_tx_sta_fifo_read_completed); 146 rt2800usb_tx_sta_fifo_read_completed);
128} 147}
129 148
149static void rt2800usb_tx_sta_fifo_timeout(unsigned long data)
150{
151 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
152
153 rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO,
154 rt2800usb_tx_sta_fifo_read_completed);
155}
156
130/* 157/*
131 * Firmware functions 158 * Firmware functions
132 */ 159 */
@@ -459,6 +486,14 @@ static void rt2800usb_work_txdone(struct work_struct *work)
459 break; 486 break;
460 } 487 }
461 } 488 }
489
490 /*
491 * The hw may delay sending the packet after DMA complete
492 * if the medium is busy, thus the TX_STA_FIFO entry is
493 * also delayed -> use a timer to retrieve it.
494 */
495 if (rt2800usb_txstatus_pending(rt2x00dev))
496 mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20));
462} 497}
463 498
464/* 499/*
@@ -599,6 +634,10 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
599 __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); 634 __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags);
600 __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); 635 __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags);
601 636
637 setup_timer(&rt2x00dev->txstatus_timer,
638 rt2800usb_tx_sta_fifo_timeout,
639 (unsigned long) rt2x00dev);
640
602 /* 641 /*
603 * Set the rssi offset. 642 * Set the rssi offset.
604 */ 643 */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index e3b9b5146bf5..8f37121bb83f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -37,6 +37,7 @@
37#include <linux/etherdevice.h> 37#include <linux/etherdevice.h>
38#include <linux/input-polldev.h> 38#include <linux/input-polldev.h>
39#include <linux/kfifo.h> 39#include <linux/kfifo.h>
40#include <linux/timer.h>
40 41
41#include <net/mac80211.h> 42#include <net/mac80211.h>
42 43
@@ -924,6 +925,11 @@ struct rt2x00_dev {
924 DECLARE_KFIFO_PTR(txstatus_fifo, u32); 925 DECLARE_KFIFO_PTR(txstatus_fifo, u32);
925 926
926 /* 927 /*
928 * Timer to ensure tx status reports are read (rt2800usb).
929 */
930 struct timer_list txstatus_timer;
931
932 /*
927 * Tasklet for processing tx status reports (rt2800pci). 933 * Tasklet for processing tx status reports (rt2800pci).
928 */ 934 */
929 struct tasklet_struct txstatus_tasklet; 935 struct tasklet_struct txstatus_tasklet;
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 2e490e0998da..7776d9f1f297 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -1071,6 +1071,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
1071 /* 1071 /*
1072 * Stop all work. 1072 * Stop all work.
1073 */ 1073 */
1074 del_timer_sync(&rt2x00dev->txstatus_timer);
1074 cancel_work_sync(&rt2x00dev->intf_work); 1075 cancel_work_sync(&rt2x00dev->intf_work);
1075 if (rt2x00_is_usb(rt2x00dev)) { 1076 if (rt2x00_is_usb(rt2x00dev)) {
1076 cancel_work_sync(&rt2x00dev->rxdone_work); 1077 cancel_work_sync(&rt2x00dev->rxdone_work);
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 14736e217947..34b8a887831b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -280,7 +280,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
280 * Schedule the delayed work for reading the TX status 280 * Schedule the delayed work for reading the TX status
281 * from the device. 281 * from the device.
282 */ 282 */
283 queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); 283 if (!test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags) ||
284 !kfifo_is_empty(&rt2x00dev->txstatus_fifo))
285 queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
284} 286}
285 287
286static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data) 288static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data)
@@ -816,6 +818,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
816 818
817 INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone); 819 INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone);
818 INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone); 820 INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone);
821 init_timer(&rt2x00dev->txstatus_timer);
819 822
820 retval = rt2x00usb_alloc_reg(rt2x00dev); 823 retval = rt2x00usb_alloc_reg(rt2x00dev);
821 if (retval) 824 if (retval)