aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00
diff options
context:
space:
mode:
authorJohannes Stezenbach <js@sig21.net>2011-04-18 09:30:36 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-04-19 15:39:35 -0400
commitf0187a1987ed6524518ff2a533eaf8394ac1a500 (patch)
tree0a7afe2f25e10c3be912103afb6bec7586868d94 /drivers/net/wireless/rt2x00
parent6e6d6932a3f525d734f6c2f5845e9cadfaeddce9 (diff)
rt2800usb: add timer to handle TX_STA_FIFO
TX status is reported by the hardware when a packet has been sent (or after TX failed after possible retries), which is some time after the DMA completion. Since the rt2800usb hardware can not signal interrupts we have to use a timer, otherwise the TX status would only be read by the next packet's TX DMA completion, or by the watchdog thread. Signed-off-by: Johannes Stezenbach <js@sig21.net> Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00')
-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)