aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00
diff options
context:
space:
mode:
authorJohannes Stezenbach <js@sig21.net>2011-04-18 09:29:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-04-19 15:39:30 -0400
commit75256f0348d38f414b7ac50ac78d4a4532bb6762 (patch)
treef441df9a73990fd0badb57e5159df2b1257309f0 /drivers/net/wireless/rt2x00
parent0e0d39e5f3a3e59c8513b59d4feeeadcb93b707d (diff)
rt2x00: fix queue timeout checks
Add a timestamp to each queue entry which is updated whenever the status of the entry changes, and remove the per-queue timestamps. The previous check was incorrect and caused both false positives and false negatives. With the corrected check it comes apparent that the TX status usually times out on rt2800usb unless there is sufficient traffic (i.e. the next TX will complete the previous TX status). 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/rt2x00dev.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c11
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h23
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c20
5 files changed, 43 insertions, 25 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index af25b0152cbc..2e490e0998da 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -225,7 +225,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
225void rt2x00lib_dmastart(struct queue_entry *entry) 225void rt2x00lib_dmastart(struct queue_entry *entry)
226{ 226{
227 set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); 227 set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
228 rt2x00queue_index_inc(entry->queue, Q_INDEX); 228 rt2x00queue_index_inc(entry, Q_INDEX);
229} 229}
230EXPORT_SYMBOL_GPL(rt2x00lib_dmastart); 230EXPORT_SYMBOL_GPL(rt2x00lib_dmastart);
231 231
@@ -233,7 +233,7 @@ void rt2x00lib_dmadone(struct queue_entry *entry)
233{ 233{
234 set_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags); 234 set_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags);
235 clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); 235 clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
236 rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE); 236 rt2x00queue_index_inc(entry, Q_INDEX_DMA_DONE);
237} 237}
238EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); 238EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
239 239
@@ -392,7 +392,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
392 392
393 rt2x00dev->ops->lib->clear_entry(entry); 393 rt2x00dev->ops->lib->clear_entry(entry);
394 394
395 rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); 395 rt2x00queue_index_inc(entry, Q_INDEX_DONE);
396 396
397 /* 397 /*
398 * If the data queue was below the threshold before the txdone 398 * If the data queue was below the threshold before the txdone
@@ -559,7 +559,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry)
559 559
560submit_entry: 560submit_entry:
561 entry->flags = 0; 561 entry->flags = 0;
562 rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); 562 rt2x00queue_index_inc(entry, Q_INDEX_DONE);
563 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && 563 if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
564 test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 564 test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
565 rt2x00dev->ops->lib->clear_entry(entry); 565 rt2x00dev->ops->lib->clear_entry(entry);
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index bbee2cd40993..57ede6ccf40c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -175,14 +175,14 @@ int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev,
175 175
176/** 176/**
177 * rt2x00queue_index_inc - Index incrementation function 177 * rt2x00queue_index_inc - Index incrementation function
178 * @queue: Queue (&struct data_queue) to perform the action on. 178 * @entry: Queue entry (&struct queue_entry) to perform the action on.
179 * @index: Index type (&enum queue_index) to perform the action on. 179 * @index: Index type (&enum queue_index) to perform the action on.
180 * 180 *
181 * This function will increase the requested index on the queue, 181 * This function will increase the requested index on the entry's queue,
182 * it will grab the appropriate locks and handle queue overflow events by 182 * it will grab the appropriate locks and handle queue overflow events by
183 * resetting the index to the start of the queue. 183 * resetting the index to the start of the queue.
184 */ 184 */
185void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); 185void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index);
186 186
187/** 187/**
188 * rt2x00queue_init_queues - Initialize all data queues 188 * rt2x00queue_init_queues - Initialize all data queues
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 458bb489bc7c..df8817fed09e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -561,7 +561,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
561 561
562 set_bit(ENTRY_DATA_PENDING, &entry->flags); 562 set_bit(ENTRY_DATA_PENDING, &entry->flags);
563 563
564 rt2x00queue_index_inc(queue, Q_INDEX); 564 rt2x00queue_index_inc(entry, Q_INDEX);
565 rt2x00queue_write_tx_descriptor(entry, &txdesc); 565 rt2x00queue_write_tx_descriptor(entry, &txdesc);
566 rt2x00queue_kick_tx_queue(queue, &txdesc); 566 rt2x00queue_kick_tx_queue(queue, &txdesc);
567 567
@@ -727,8 +727,9 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
727} 727}
728EXPORT_SYMBOL_GPL(rt2x00queue_get_entry); 728EXPORT_SYMBOL_GPL(rt2x00queue_get_entry);
729 729
730void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) 730void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index)
731{ 731{
732 struct data_queue *queue = entry->queue;
732 unsigned long irqflags; 733 unsigned long irqflags;
733 734
734 if (unlikely(index >= Q_INDEX_MAX)) { 735 if (unlikely(index >= Q_INDEX_MAX)) {
@@ -743,7 +744,7 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
743 if (queue->index[index] >= queue->limit) 744 if (queue->index[index] >= queue->limit)
744 queue->index[index] = 0; 745 queue->index[index] = 0;
745 746
746 queue->last_action[index] = jiffies; 747 entry->last_action = jiffies;
747 748
748 if (index == Q_INDEX) { 749 if (index == Q_INDEX) {
749 queue->length++; 750 queue->length++;
@@ -969,10 +970,8 @@ static void rt2x00queue_reset(struct data_queue *queue)
969 queue->count = 0; 970 queue->count = 0;
970 queue->length = 0; 971 queue->length = 0;
971 972
972 for (i = 0; i < Q_INDEX_MAX; i++) { 973 for (i = 0; i < Q_INDEX_MAX; i++)
973 queue->index[i] = 0; 974 queue->index[i] = 0;
974 queue->last_action[i] = jiffies;
975 }
976 975
977 spin_unlock_irqrestore(&queue->index_lock, irqflags); 976 spin_unlock_irqrestore(&queue->index_lock, irqflags);
978} 977}
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 6b664525135d..36f4d03eff61 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -364,6 +364,7 @@ enum queue_entry_flags {
364 * struct queue_entry: Entry inside the &struct data_queue 364 * struct queue_entry: Entry inside the &struct data_queue
365 * 365 *
366 * @flags: Entry flags, see &enum queue_entry_flags. 366 * @flags: Entry flags, see &enum queue_entry_flags.
367 * @last_action: Timestamp of last change.
367 * @queue: The data queue (&struct data_queue) to which this entry belongs. 368 * @queue: The data queue (&struct data_queue) to which this entry belongs.
368 * @skb: The buffer which is currently being transmitted (for TX queue), 369 * @skb: The buffer which is currently being transmitted (for TX queue),
369 * or used to directly recieve data in (for RX queue). 370 * or used to directly recieve data in (for RX queue).
@@ -373,6 +374,7 @@ enum queue_entry_flags {
373 */ 374 */
374struct queue_entry { 375struct queue_entry {
375 unsigned long flags; 376 unsigned long flags;
377 unsigned long last_action;
376 378
377 struct data_queue *queue; 379 struct data_queue *queue;
378 380
@@ -463,7 +465,6 @@ struct data_queue {
463 unsigned short threshold; 465 unsigned short threshold;
464 unsigned short length; 466 unsigned short length;
465 unsigned short index[Q_INDEX_MAX]; 467 unsigned short index[Q_INDEX_MAX];
466 unsigned long last_action[Q_INDEX_MAX];
467 468
468 unsigned short txop; 469 unsigned short txop;
469 unsigned short aifs; 470 unsigned short aifs;
@@ -635,22 +636,24 @@ static inline int rt2x00queue_threshold(struct data_queue *queue)
635 636
636/** 637/**
637 * rt2x00queue_status_timeout - Check if a timeout occured for STATUS reports 638 * rt2x00queue_status_timeout - Check if a timeout occured for STATUS reports
638 * @queue: Queue to check. 639 * @entry: Queue entry to check.
639 */ 640 */
640static inline int rt2x00queue_status_timeout(struct data_queue *queue) 641static inline int rt2x00queue_status_timeout(struct queue_entry *entry)
641{ 642{
642 return time_after(queue->last_action[Q_INDEX_DMA_DONE], 643 if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
643 queue->last_action[Q_INDEX_DONE] + (HZ / 10)); 644 return false;
645 return time_after(jiffies, entry->last_action + msecs_to_jiffies(100));
644} 646}
645 647
646/** 648/**
647 * rt2x00queue_timeout - Check if a timeout occured for DMA transfers 649 * rt2x00queuedma__timeout - Check if a timeout occured for DMA transfers
648 * @queue: Queue to check. 650 * @entry: Queue entry to check.
649 */ 651 */
650static inline int rt2x00queue_dma_timeout(struct data_queue *queue) 652static inline int rt2x00queue_dma_timeout(struct queue_entry *entry)
651{ 653{
652 return time_after(queue->last_action[Q_INDEX], 654 if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
653 queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10)); 655 return false;
656 return time_after(jiffies, entry->last_action + msecs_to_jiffies(100));
654} 657}
655 658
656/** 659/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 5fbab6f19706..14736e217947 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -521,15 +521,31 @@ static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
521 queue_work(queue->rt2x00dev->workqueue, &queue->rt2x00dev->txdone_work); 521 queue_work(queue->rt2x00dev->workqueue, &queue->rt2x00dev->txdone_work);
522} 522}
523 523
524static int rt2x00usb_status_timeout(struct data_queue *queue)
525{
526 struct queue_entry *entry;
527
528 entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
529 return rt2x00queue_status_timeout(entry);
530}
531
532static int rt2x00usb_dma_timeout(struct data_queue *queue)
533{
534 struct queue_entry *entry;
535
536 entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE);
537 return rt2x00queue_dma_timeout(entry);
538}
539
524void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) 540void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
525{ 541{
526 struct data_queue *queue; 542 struct data_queue *queue;
527 543
528 tx_queue_for_each(rt2x00dev, queue) { 544 tx_queue_for_each(rt2x00dev, queue) {
529 if (!rt2x00queue_empty(queue)) { 545 if (!rt2x00queue_empty(queue)) {
530 if (rt2x00queue_dma_timeout(queue)) 546 if (rt2x00usb_dma_timeout(queue))
531 rt2x00usb_watchdog_tx_dma(queue); 547 rt2x00usb_watchdog_tx_dma(queue);
532 if (rt2x00queue_status_timeout(queue)) 548 if (rt2x00usb_status_timeout(queue))
533 rt2x00usb_watchdog_tx_status(queue); 549 rt2x00usb_watchdog_tx_status(queue);
534 } 550 }
535 } 551 }