diff options
author | Ivo van Doorn <ivdoorn@gmail.com> | 2010-08-23 13:54:21 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-08-25 14:34:54 -0400 |
commit | 5eb7efe8a4807d98a277280e1317e5094eedfb6b (patch) | |
tree | 124a1a599ff718cfd84bb441202fe251f65bda19 /drivers/net/wireless/rt2x00/rt2x00queue.c | |
parent | ee1e755f84dfd5d482076c642fac830aafdc482b (diff) |
rt2x00: Move direct access to queue->entries to rt2x00queue.c
All access to queue->entries through the Q_INDEX/Q_INDEX_DONE
variables must be done using spinlock protection. It is best
to manage this completely from rt2x00queue.c.
For safely looping through all entries in the queue, the function
rt2x00queue_for_each_entry is added which will walk from from a index
range in a safe manner.
This also fixes rt2x00usb which walked the entries list from
0 to length to kill each entry (killing entries must be done
from Q_INDEX_DONE to Q_INDEX to enforce TX status reporting to
occur in the correct order.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Acked-by: Gertjan van Wingerde <gwingerde@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00queue.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 189eaf72967e..7fb9b6179af1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -625,6 +625,51 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, | |||
625 | return 0; | 625 | return 0; |
626 | } | 626 | } |
627 | 627 | ||
628 | void rt2x00queue_for_each_entry(struct data_queue *queue, | ||
629 | enum queue_index start, | ||
630 | enum queue_index end, | ||
631 | void (*fn)(struct queue_entry *entry)) | ||
632 | { | ||
633 | unsigned long irqflags; | ||
634 | unsigned int index_start; | ||
635 | unsigned int index_end; | ||
636 | unsigned int i; | ||
637 | |||
638 | if (unlikely(start >= Q_INDEX_MAX || end >= Q_INDEX_MAX)) { | ||
639 | ERROR(queue->rt2x00dev, | ||
640 | "Entry requested from invalid index range (%d - %d)\n", | ||
641 | start, end); | ||
642 | return; | ||
643 | } | ||
644 | |||
645 | /* | ||
646 | * Only protect the range we are going to loop over, | ||
647 | * if during our loop a extra entry is set to pending | ||
648 | * it should not be kicked during this run, since it | ||
649 | * is part of another TX operation. | ||
650 | */ | ||
651 | spin_lock_irqsave(&queue->lock, irqflags); | ||
652 | index_start = queue->index[start]; | ||
653 | index_end = queue->index[end]; | ||
654 | spin_unlock_irqrestore(&queue->lock, irqflags); | ||
655 | |||
656 | /* | ||
657 | * Start from the TX done pointer, this guarentees that we will | ||
658 | * send out all frames in the correct order. | ||
659 | */ | ||
660 | if (index_start < index_end) { | ||
661 | for (i = index_start; i < index_end; i++) | ||
662 | fn(&queue->entries[i]); | ||
663 | } else { | ||
664 | for (i = index_start; i < queue->limit; i++) | ||
665 | fn(&queue->entries[i]); | ||
666 | |||
667 | for (i = 0; i < index_end; i++) | ||
668 | fn(&queue->entries[i]); | ||
669 | } | ||
670 | } | ||
671 | EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry); | ||
672 | |||
628 | struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, | 673 | struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, |
629 | const enum data_queue_qid queue) | 674 | const enum data_queue_qid queue) |
630 | { | 675 | { |