diff options
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00.h | 52 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00config.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00debug.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 22 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00lib.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00mac.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 130 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.h | 23 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00usb.c | 190 |
9 files changed, 302 insertions, 141 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index b72f59ba4e1e..ac7c3d80300e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -1073,6 +1073,58 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, | |||
1073 | struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, | 1073 | struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, |
1074 | enum queue_index index); | 1074 | enum queue_index index); |
1075 | 1075 | ||
1076 | /** | ||
1077 | * rt2x00queue_pause_queue - Pause a data queue | ||
1078 | * @queue: Pointer to &struct data_queue. | ||
1079 | * | ||
1080 | * This function will pause the data queue locally, preventing | ||
1081 | * new frames to be added to the queue (while the hardware is | ||
1082 | * still allowed to run). | ||
1083 | */ | ||
1084 | void rt2x00queue_pause_queue(struct data_queue *queue); | ||
1085 | |||
1086 | /** | ||
1087 | * rt2x00queue_unpause_queue - unpause a data queue | ||
1088 | * @queue: Pointer to &struct data_queue. | ||
1089 | * | ||
1090 | * This function will unpause the data queue locally, allowing | ||
1091 | * new frames to be added to the queue again. | ||
1092 | */ | ||
1093 | void rt2x00queue_unpause_queue(struct data_queue *queue); | ||
1094 | |||
1095 | /** | ||
1096 | * rt2x00queue_start_queue - Start a data queue | ||
1097 | * @queue: Pointer to &struct data_queue. | ||
1098 | * | ||
1099 | * This function will start handling all pending frames in the queue. | ||
1100 | */ | ||
1101 | void rt2x00queue_start_queue(struct data_queue *queue); | ||
1102 | |||
1103 | /** | ||
1104 | * rt2x00queue_stop_queue - Halt a data queue | ||
1105 | * @queue: Pointer to &struct data_queue. | ||
1106 | * | ||
1107 | * This function will stop all pending frames in the queue. | ||
1108 | */ | ||
1109 | void rt2x00queue_stop_queue(struct data_queue *queue); | ||
1110 | |||
1111 | /** | ||
1112 | * rt2x00queue_start_queues - Start all data queues | ||
1113 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | ||
1114 | * | ||
1115 | * This function will loop through all available queues to start them | ||
1116 | */ | ||
1117 | void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev); | ||
1118 | |||
1119 | /** | ||
1120 | * rt2x00queue_stop_queues - Halt all data queues | ||
1121 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | ||
1122 | * | ||
1123 | * This function will loop through all available queues to stop | ||
1124 | * any pending frames. | ||
1125 | */ | ||
1126 | void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev); | ||
1127 | |||
1076 | /* | 1128 | /* |
1077 | * Debugfs handlers. | 1129 | * Debugfs handlers. |
1078 | */ | 1130 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index d2f1f0ad2bc8..70ca9379833b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c | |||
@@ -146,7 +146,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, | |||
146 | * else the changes will be ignored by the device. | 146 | * else the changes will be ignored by the device. |
147 | */ | 147 | */ |
148 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | 148 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
149 | rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx); | 149 | rt2x00queue_stop_queue(rt2x00dev->rx); |
150 | 150 | ||
151 | /* | 151 | /* |
152 | * Write new antenna setup to device and reset the link tuner. | 152 | * Write new antenna setup to device and reset the link tuner. |
@@ -160,7 +160,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, | |||
160 | memcpy(active, &config, sizeof(config)); | 160 | memcpy(active, &config, sizeof(config)); |
161 | 161 | ||
162 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | 162 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
163 | rt2x00dev->ops->lib->start_queue(rt2x00dev->rx); | 163 | rt2x00queue_start_queue(rt2x00dev->rx); |
164 | } | 164 | } |
165 | 165 | ||
166 | void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, | 166 | void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 64dfb1f6823e..c92db3264741 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c | |||
@@ -339,12 +339,13 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file, | |||
339 | return -ENOMEM; | 339 | return -ENOMEM; |
340 | 340 | ||
341 | temp = data + | 341 | temp = data + |
342 | sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdma done\tdone\n"); | 342 | sprintf(data, "qid\tflags\t\tcount\tlimit\tlength\tindex\tdma done\tdone\n"); |
343 | 343 | ||
344 | queue_for_each(intf->rt2x00dev, queue) { | 344 | queue_for_each(intf->rt2x00dev, queue) { |
345 | spin_lock_irqsave(&queue->index_lock, irqflags); | 345 | spin_lock_irqsave(&queue->index_lock, irqflags); |
346 | 346 | ||
347 | temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid, | 347 | temp += sprintf(temp, "%d\t0x%.8x\t%d\t%d\t%d\t%d\t%d\t\t%d\n", |
348 | queue->qid, (unsigned int)queue->flags, | ||
348 | queue->count, queue->limit, queue->length, | 349 | queue->count, queue->limit, queue->length, |
349 | queue->index[Q_INDEX], | 350 | queue->index[Q_INDEX], |
350 | queue->index[Q_INDEX_DMA_DONE], | 351 | queue->index[Q_INDEX_DMA_DONE], |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 2c5f246408e8..e42816286ffc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -66,9 +66,9 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) | |||
66 | set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags); | 66 | set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags); |
67 | 67 | ||
68 | /* | 68 | /* |
69 | * Enable RX. | 69 | * Enable queues. |
70 | */ | 70 | */ |
71 | rt2x00dev->ops->lib->start_queue(rt2x00dev->rx); | 71 | rt2x00queue_start_queues(rt2x00dev); |
72 | rt2x00link_start_tuner(rt2x00dev); | 72 | rt2x00link_start_tuner(rt2x00dev); |
73 | 73 | ||
74 | /* | 74 | /* |
@@ -76,11 +76,6 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) | |||
76 | */ | 76 | */ |
77 | rt2x00link_start_watchdog(rt2x00dev); | 77 | rt2x00link_start_watchdog(rt2x00dev); |
78 | 78 | ||
79 | /* | ||
80 | * Start the TX queues. | ||
81 | */ | ||
82 | ieee80211_wake_queues(rt2x00dev->hw); | ||
83 | |||
84 | return 0; | 79 | return 0; |
85 | } | 80 | } |
86 | 81 | ||
@@ -90,21 +85,15 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) | |||
90 | return; | 85 | return; |
91 | 86 | ||
92 | /* | 87 | /* |
93 | * Stop the TX queues in mac80211. | ||
94 | */ | ||
95 | ieee80211_stop_queues(rt2x00dev->hw); | ||
96 | rt2x00queue_stop_queues(rt2x00dev); | ||
97 | |||
98 | /* | ||
99 | * Stop watchdog monitoring. | 88 | * Stop watchdog monitoring. |
100 | */ | 89 | */ |
101 | rt2x00link_stop_watchdog(rt2x00dev); | 90 | rt2x00link_stop_watchdog(rt2x00dev); |
102 | 91 | ||
103 | /* | 92 | /* |
104 | * Disable RX. | 93 | * Stop all queues |
105 | */ | 94 | */ |
106 | rt2x00link_stop_tuner(rt2x00dev); | 95 | rt2x00link_stop_tuner(rt2x00dev); |
107 | rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx); | 96 | rt2x00queue_stop_queues(rt2x00dev); |
108 | 97 | ||
109 | /* | 98 | /* |
110 | * Disable radio. | 99 | * Disable radio. |
@@ -249,7 +238,6 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
249 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | 238 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
250 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); | 239 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); |
251 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); | 240 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); |
252 | enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); | ||
253 | unsigned int header_length, i; | 241 | unsigned int header_length, i; |
254 | u8 rate_idx, rate_flags, retry_rates; | 242 | u8 rate_idx, rate_flags, retry_rates; |
255 | u8 skbdesc_flags = skbdesc->flags; | 243 | u8 skbdesc_flags = skbdesc->flags; |
@@ -403,7 +391,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
403 | * is reenabled when the txdone handler has finished. | 391 | * is reenabled when the txdone handler has finished. |
404 | */ | 392 | */ |
405 | if (!rt2x00queue_threshold(entry->queue)) | 393 | if (!rt2x00queue_threshold(entry->queue)) |
406 | ieee80211_wake_queue(rt2x00dev->hw, qid); | 394 | rt2x00queue_unpause_queue(entry->queue); |
407 | } | 395 | } |
408 | EXPORT_SYMBOL_GPL(rt2x00lib_txdone); | 396 | EXPORT_SYMBOL_GPL(rt2x00lib_txdone); |
409 | 397 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 2cf68f82674b..a105c500627b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h | |||
@@ -178,15 +178,6 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, | |||
178 | void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); | 178 | void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); |
179 | 179 | ||
180 | /** | 180 | /** |
181 | * rt2x00queue_stop_queues - Halt all data queues | ||
182 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | ||
183 | * | ||
184 | * This function will loop through all available queues to stop | ||
185 | * any pending outgoing frames. | ||
186 | */ | ||
187 | void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev); | ||
188 | |||
189 | /** | ||
190 | * rt2x00queue_init_queues - Initialize all data queues | 181 | * rt2x00queue_init_queues - Initialize all data queues |
191 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | 182 | * @rt2x00dev: Pointer to &struct rt2x00_dev. |
192 | * | 183 | * |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 6713f1ab1284..c4abb204aeda 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -104,7 +104,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
104 | struct rt2x00_dev *rt2x00dev = hw->priv; | 104 | struct rt2x00_dev *rt2x00dev = hw->priv; |
105 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 105 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
106 | enum data_queue_qid qid = skb_get_queue_mapping(skb); | 106 | enum data_queue_qid qid = skb_get_queue_mapping(skb); |
107 | struct data_queue *queue; | 107 | struct data_queue *queue = NULL; |
108 | 108 | ||
109 | /* | 109 | /* |
110 | * Mac80211 might be calling this function while we are trying | 110 | * Mac80211 might be calling this function while we are trying |
@@ -153,7 +153,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
153 | goto exit_fail; | 153 | goto exit_fail; |
154 | 154 | ||
155 | if (rt2x00queue_threshold(queue)) | 155 | if (rt2x00queue_threshold(queue)) |
156 | ieee80211_stop_queue(rt2x00dev->hw, qid); | 156 | rt2x00queue_pause_queue(queue); |
157 | 157 | ||
158 | return NETDEV_TX_OK; | 158 | return NETDEV_TX_OK; |
159 | 159 | ||
@@ -352,7 +352,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) | |||
352 | * if for any reason the link tuner must be reset, this will be | 352 | * if for any reason the link tuner must be reset, this will be |
353 | * handled by rt2x00lib_config(). | 353 | * handled by rt2x00lib_config(). |
354 | */ | 354 | */ |
355 | rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx); | 355 | rt2x00queue_stop_queue(rt2x00dev->rx); |
356 | 356 | ||
357 | /* | 357 | /* |
358 | * When we've just turned on the radio, we want to reprogram | 358 | * When we've just turned on the radio, we want to reprogram |
@@ -370,7 +370,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) | |||
370 | rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant); | 370 | rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant); |
371 | 371 | ||
372 | /* Turn RX back on */ | 372 | /* Turn RX back on */ |
373 | rt2x00dev->ops->lib->start_queue(rt2x00dev->rx); | 373 | rt2x00queue_start_queue(rt2x00dev->rx); |
374 | 374 | ||
375 | return 0; | 375 | return 0; |
376 | } | 376 | } |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 2af6cea0d2da..558965fb41b3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -585,7 +585,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, | |||
585 | rt2x00queue_free_skb(intf->beacon); | 585 | rt2x00queue_free_skb(intf->beacon); |
586 | 586 | ||
587 | if (!enable_beacon) { | 587 | if (!enable_beacon) { |
588 | rt2x00dev->ops->lib->stop_queue(intf->beacon->queue); | 588 | rt2x00queue_stop_queue(intf->beacon->queue); |
589 | mutex_unlock(&intf->beacon_skb_mutex); | 589 | mutex_unlock(&intf->beacon_skb_mutex); |
590 | return 0; | 590 | return 0; |
591 | } | 591 | } |
@@ -738,6 +738,125 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) | |||
738 | spin_unlock_irqrestore(&queue->index_lock, irqflags); | 738 | spin_unlock_irqrestore(&queue->index_lock, irqflags); |
739 | } | 739 | } |
740 | 740 | ||
741 | void rt2x00queue_pause_queue(struct data_queue *queue) | ||
742 | { | ||
743 | if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || | ||
744 | !test_bit(QUEUE_STARTED, &queue->flags) || | ||
745 | test_and_set_bit(QUEUE_PAUSED, &queue->flags)) | ||
746 | return; | ||
747 | |||
748 | switch (queue->qid) { | ||
749 | case QID_AC_BE: | ||
750 | case QID_AC_BK: | ||
751 | case QID_AC_VI: | ||
752 | case QID_AC_VO: | ||
753 | /* | ||
754 | * For TX queues, we have to disable the queue | ||
755 | * inside mac80211. | ||
756 | */ | ||
757 | ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid); | ||
758 | break; | ||
759 | default: | ||
760 | break; | ||
761 | } | ||
762 | } | ||
763 | EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue); | ||
764 | |||
765 | void rt2x00queue_unpause_queue(struct data_queue *queue) | ||
766 | { | ||
767 | if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || | ||
768 | !test_bit(QUEUE_STARTED, &queue->flags) || | ||
769 | !test_and_clear_bit(QUEUE_PAUSED, &queue->flags)) | ||
770 | return; | ||
771 | |||
772 | switch (queue->qid) { | ||
773 | case QID_AC_BE: | ||
774 | case QID_AC_BK: | ||
775 | case QID_AC_VI: | ||
776 | case QID_AC_VO: | ||
777 | /* | ||
778 | * For TX queues, we have to enable the queue | ||
779 | * inside mac80211. | ||
780 | */ | ||
781 | ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid); | ||
782 | break; | ||
783 | default: | ||
784 | break; | ||
785 | } | ||
786 | } | ||
787 | EXPORT_SYMBOL_GPL(rt2x00queue_unpause_queue); | ||
788 | |||
789 | void rt2x00queue_start_queue(struct data_queue *queue) | ||
790 | { | ||
791 | mutex_lock(&queue->status_lock); | ||
792 | |||
793 | if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || | ||
794 | test_and_set_bit(QUEUE_STARTED, &queue->flags)) { | ||
795 | mutex_unlock(&queue->status_lock); | ||
796 | return; | ||
797 | } | ||
798 | |||
799 | set_bit(QUEUE_PAUSED, &queue->flags); | ||
800 | |||
801 | queue->rt2x00dev->ops->lib->start_queue(queue); | ||
802 | |||
803 | rt2x00queue_unpause_queue(queue); | ||
804 | |||
805 | mutex_unlock(&queue->status_lock); | ||
806 | } | ||
807 | EXPORT_SYMBOL_GPL(rt2x00queue_start_queue); | ||
808 | |||
809 | void rt2x00queue_stop_queue(struct data_queue *queue) | ||
810 | { | ||
811 | mutex_lock(&queue->status_lock); | ||
812 | |||
813 | if (!test_and_clear_bit(QUEUE_STARTED, &queue->flags)) { | ||
814 | mutex_unlock(&queue->status_lock); | ||
815 | return; | ||
816 | } | ||
817 | |||
818 | rt2x00queue_pause_queue(queue); | ||
819 | |||
820 | queue->rt2x00dev->ops->lib->stop_queue(queue); | ||
821 | |||
822 | mutex_unlock(&queue->status_lock); | ||
823 | } | ||
824 | EXPORT_SYMBOL_GPL(rt2x00queue_stop_queue); | ||
825 | |||
826 | void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev) | ||
827 | { | ||
828 | struct data_queue *queue; | ||
829 | |||
830 | /* | ||
831 | * rt2x00queue_start_queue will call ieee80211_wake_queue | ||
832 | * for each queue after is has been properly initialized. | ||
833 | */ | ||
834 | tx_queue_for_each(rt2x00dev, queue) | ||
835 | rt2x00queue_start_queue(queue); | ||
836 | |||
837 | rt2x00queue_start_queue(rt2x00dev->rx); | ||
838 | } | ||
839 | EXPORT_SYMBOL_GPL(rt2x00queue_start_queues); | ||
840 | |||
841 | void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev) | ||
842 | { | ||
843 | struct data_queue *queue; | ||
844 | |||
845 | /* | ||
846 | * rt2x00queue_stop_queue will call ieee80211_stop_queue | ||
847 | * as well, but we are completely shutting doing everything | ||
848 | * now, so it is much safer to stop all TX queues at once, | ||
849 | * and use rt2x00queue_stop_queue for cleaning up. | ||
850 | */ | ||
851 | ieee80211_stop_queues(rt2x00dev->hw); | ||
852 | |||
853 | tx_queue_for_each(rt2x00dev, queue) | ||
854 | rt2x00queue_stop_queue(queue); | ||
855 | |||
856 | rt2x00queue_stop_queue(rt2x00dev->rx); | ||
857 | } | ||
858 | EXPORT_SYMBOL_GPL(rt2x00queue_stop_queues); | ||
859 | |||
741 | static void rt2x00queue_reset(struct data_queue *queue) | 860 | static void rt2x00queue_reset(struct data_queue *queue) |
742 | { | 861 | { |
743 | unsigned long irqflags; | 862 | unsigned long irqflags; |
@@ -756,14 +875,6 @@ static void rt2x00queue_reset(struct data_queue *queue) | |||
756 | spin_unlock_irqrestore(&queue->index_lock, irqflags); | 875 | spin_unlock_irqrestore(&queue->index_lock, irqflags); |
757 | } | 876 | } |
758 | 877 | ||
759 | void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev) | ||
760 | { | ||
761 | struct data_queue *queue; | ||
762 | |||
763 | txall_queue_for_each(rt2x00dev, queue) | ||
764 | rt2x00dev->ops->lib->stop_queue(queue); | ||
765 | } | ||
766 | |||
767 | void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev) | 878 | void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev) |
768 | { | 879 | { |
769 | struct data_queue *queue; | 880 | struct data_queue *queue; |
@@ -905,6 +1016,7 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev) | |||
905 | static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, | 1016 | static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, |
906 | struct data_queue *queue, enum data_queue_qid qid) | 1017 | struct data_queue *queue, enum data_queue_qid qid) |
907 | { | 1018 | { |
1019 | mutex_init(&queue->status_lock); | ||
908 | spin_lock_init(&queue->index_lock); | 1020 | spin_lock_init(&queue->index_lock); |
909 | 1021 | ||
910 | queue->rt2x00dev = rt2x00dev; | 1022 | queue->rt2x00dev = rt2x00dev; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 29b051ac6401..baa39b75430c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h | |||
@@ -392,12 +392,32 @@ enum queue_index { | |||
392 | }; | 392 | }; |
393 | 393 | ||
394 | /** | 394 | /** |
395 | * enum data_queue_flags: Status flags for data queues | ||
396 | * | ||
397 | * @QUEUE_STARTED: The queue has been started. Fox RX queues this means the | ||
398 | * device might be DMA'ing skbuffers. TX queues will accept skbuffers to | ||
399 | * be transmitted and beacon queues will start beaconing the configured | ||
400 | * beacons. | ||
401 | * @QUEUE_PAUSED: The queue has been started but is currently paused. | ||
402 | * When this bit is set, the queue has been stopped in mac80211, | ||
403 | * preventing new frames to be enqueued. However, a few frames | ||
404 | * might still appear shortly after the pausing... | ||
405 | */ | ||
406 | enum data_queue_flags { | ||
407 | QUEUE_STARTED, | ||
408 | QUEUE_PAUSED, | ||
409 | }; | ||
410 | |||
411 | /** | ||
395 | * struct data_queue: Data queue | 412 | * struct data_queue: Data queue |
396 | * | 413 | * |
397 | * @rt2x00dev: Pointer to main &struct rt2x00dev where this queue belongs to. | 414 | * @rt2x00dev: Pointer to main &struct rt2x00dev where this queue belongs to. |
398 | * @entries: Base address of the &struct queue_entry which are | 415 | * @entries: Base address of the &struct queue_entry which are |
399 | * part of this queue. | 416 | * part of this queue. |
400 | * @qid: The queue identification, see &enum data_queue_qid. | 417 | * @qid: The queue identification, see &enum data_queue_qid. |
418 | * @flags: Entry flags, see &enum queue_entry_flags. | ||
419 | * @status_lock: The mutex for protecting the start/stop/flush | ||
420 | * handling on this queue. | ||
401 | * @index_lock: Spinlock to protect index handling. Whenever @index, @index_done or | 421 | * @index_lock: Spinlock to protect index handling. Whenever @index, @index_done or |
402 | * @index_crypt needs to be changed this lock should be grabbed to prevent | 422 | * @index_crypt needs to be changed this lock should be grabbed to prevent |
403 | * index corruption due to concurrency. | 423 | * index corruption due to concurrency. |
@@ -421,8 +441,11 @@ struct data_queue { | |||
421 | struct queue_entry *entries; | 441 | struct queue_entry *entries; |
422 | 442 | ||
423 | enum data_queue_qid qid; | 443 | enum data_queue_qid qid; |
444 | unsigned long flags; | ||
424 | 445 | ||
446 | struct mutex status_lock; | ||
425 | spinlock_t index_lock; | 447 | spinlock_t index_lock; |
448 | |||
426 | unsigned int count; | 449 | unsigned int count; |
427 | unsigned short limit; | 450 | unsigned short limit; |
428 | unsigned short threshold; | 451 | unsigned short threshold; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index d4361dc0773e..fca29ae57e71 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c | |||
@@ -261,6 +261,89 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) | |||
261 | } | 261 | } |
262 | } | 262 | } |
263 | 263 | ||
264 | /* | ||
265 | * RX data handlers. | ||
266 | */ | ||
267 | static void rt2x00usb_work_rxdone(struct work_struct *work) | ||
268 | { | ||
269 | struct rt2x00_dev *rt2x00dev = | ||
270 | container_of(work, struct rt2x00_dev, rxdone_work); | ||
271 | struct queue_entry *entry; | ||
272 | struct skb_frame_desc *skbdesc; | ||
273 | u8 rxd[32]; | ||
274 | |||
275 | while (!rt2x00queue_empty(rt2x00dev->rx)) { | ||
276 | entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE); | ||
277 | |||
278 | if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) | ||
279 | break; | ||
280 | |||
281 | /* | ||
282 | * Fill in desc fields of the skb descriptor | ||
283 | */ | ||
284 | skbdesc = get_skb_frame_desc(entry->skb); | ||
285 | skbdesc->desc = rxd; | ||
286 | skbdesc->desc_len = entry->queue->desc_size; | ||
287 | |||
288 | /* | ||
289 | * Send the frame to rt2x00lib for further processing. | ||
290 | */ | ||
291 | rt2x00lib_rxdone(entry); | ||
292 | } | ||
293 | } | ||
294 | |||
295 | static void rt2x00usb_interrupt_rxdone(struct urb *urb) | ||
296 | { | ||
297 | struct queue_entry *entry = (struct queue_entry *)urb->context; | ||
298 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | ||
299 | |||
300 | if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) | ||
301 | return; | ||
302 | |||
303 | /* | ||
304 | * Report the frame as DMA done | ||
305 | */ | ||
306 | rt2x00lib_dmadone(entry); | ||
307 | |||
308 | /* | ||
309 | * Check if the received data is simply too small | ||
310 | * to be actually valid, or if the urb is signaling | ||
311 | * a problem. | ||
312 | */ | ||
313 | if (urb->actual_length < entry->queue->desc_size || urb->status) | ||
314 | set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); | ||
315 | |||
316 | /* | ||
317 | * Schedule the delayed work for reading the RX status | ||
318 | * from the device. | ||
319 | */ | ||
320 | ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work); | ||
321 | } | ||
322 | |||
323 | static void rt2x00usb_kick_rx_entry(struct queue_entry *entry) | ||
324 | { | ||
325 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | ||
326 | struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); | ||
327 | struct queue_entry_priv_usb *entry_priv = entry->priv_data; | ||
328 | int status; | ||
329 | |||
330 | if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) | ||
331 | return; | ||
332 | |||
333 | usb_fill_bulk_urb(entry_priv->urb, usb_dev, | ||
334 | usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint), | ||
335 | entry->skb->data, entry->skb->len, | ||
336 | rt2x00usb_interrupt_rxdone, entry); | ||
337 | |||
338 | status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC); | ||
339 | if (status) { | ||
340 | if (status == -ENODEV) | ||
341 | clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); | ||
342 | set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); | ||
343 | rt2x00lib_dmadone(entry); | ||
344 | } | ||
345 | } | ||
346 | |||
264 | void rt2x00usb_kick_queue(struct data_queue *queue) | 347 | void rt2x00usb_kick_queue(struct data_queue *queue) |
265 | { | 348 | { |
266 | switch (queue->qid) { | 349 | switch (queue->qid) { |
@@ -272,6 +355,11 @@ void rt2x00usb_kick_queue(struct data_queue *queue) | |||
272 | rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, | 355 | rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, |
273 | rt2x00usb_kick_tx_entry); | 356 | rt2x00usb_kick_tx_entry); |
274 | break; | 357 | break; |
358 | case QID_RX: | ||
359 | if (!rt2x00queue_full(queue)) | ||
360 | rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, | ||
361 | rt2x00usb_kick_rx_entry); | ||
362 | break; | ||
275 | default: | 363 | default: |
276 | break; | 364 | break; |
277 | } | 365 | } |
@@ -307,7 +395,6 @@ EXPORT_SYMBOL_GPL(rt2x00usb_stop_queue); | |||
307 | static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) | 395 | static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) |
308 | { | 396 | { |
309 | struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; | 397 | struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; |
310 | unsigned short threshold = queue->threshold; | ||
311 | 398 | ||
312 | WARNING(queue->rt2x00dev, "TX queue %d DMA timed out," | 399 | WARNING(queue->rt2x00dev, "TX queue %d DMA timed out," |
313 | " invoke forced forced reset\n", queue->qid); | 400 | " invoke forced forced reset\n", queue->qid); |
@@ -315,18 +402,8 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) | |||
315 | /* | 402 | /* |
316 | * Temporarily disable the TX queue, this will force mac80211 | 403 | * Temporarily disable the TX queue, this will force mac80211 |
317 | * to use the other queues until this queue has been restored. | 404 | * to use the other queues until this queue has been restored. |
318 | * | ||
319 | * Set the queue threshold to the queue limit. This prevents the | ||
320 | * queue from being enabled during the txdone handler. | ||
321 | */ | 405 | */ |
322 | queue->threshold = queue->limit; | 406 | rt2x00queue_stop_queue(queue); |
323 | ieee80211_stop_queue(rt2x00dev->hw, queue->qid); | ||
324 | |||
325 | /* | ||
326 | * Kill all entries in the queue, afterwards we need to | ||
327 | * wait a bit for all URBs to be cancelled. | ||
328 | */ | ||
329 | rt2x00usb_stop_queue(queue); | ||
330 | 407 | ||
331 | /* | 408 | /* |
332 | * In case that a driver has overriden the txdone_work | 409 | * In case that a driver has overriden the txdone_work |
@@ -338,8 +415,7 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) | |||
338 | * The queue has been reset, and mac80211 is allowed to use the | 415 | * The queue has been reset, and mac80211 is allowed to use the |
339 | * queue again. | 416 | * queue again. |
340 | */ | 417 | */ |
341 | queue->threshold = threshold; | 418 | rt2x00queue_start_queue(queue); |
342 | ieee80211_wake_queue(rt2x00dev->hw, queue->qid); | ||
343 | } | 419 | } |
344 | 420 | ||
345 | static void rt2x00usb_watchdog_tx_status(struct data_queue *queue) | 421 | static void rt2x00usb_watchdog_tx_status(struct data_queue *queue) |
@@ -366,73 +442,12 @@ void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) | |||
366 | EXPORT_SYMBOL_GPL(rt2x00usb_watchdog); | 442 | EXPORT_SYMBOL_GPL(rt2x00usb_watchdog); |
367 | 443 | ||
368 | /* | 444 | /* |
369 | * RX data handlers. | ||
370 | */ | ||
371 | static void rt2x00usb_work_rxdone(struct work_struct *work) | ||
372 | { | ||
373 | struct rt2x00_dev *rt2x00dev = | ||
374 | container_of(work, struct rt2x00_dev, rxdone_work); | ||
375 | struct queue_entry *entry; | ||
376 | struct skb_frame_desc *skbdesc; | ||
377 | u8 rxd[32]; | ||
378 | |||
379 | while (!rt2x00queue_empty(rt2x00dev->rx)) { | ||
380 | entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE); | ||
381 | |||
382 | if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) | ||
383 | break; | ||
384 | |||
385 | /* | ||
386 | * Fill in desc fields of the skb descriptor | ||
387 | */ | ||
388 | skbdesc = get_skb_frame_desc(entry->skb); | ||
389 | skbdesc->desc = rxd; | ||
390 | skbdesc->desc_len = entry->queue->desc_size; | ||
391 | |||
392 | /* | ||
393 | * Send the frame to rt2x00lib for further processing. | ||
394 | */ | ||
395 | rt2x00lib_rxdone(entry); | ||
396 | } | ||
397 | } | ||
398 | |||
399 | static void rt2x00usb_interrupt_rxdone(struct urb *urb) | ||
400 | { | ||
401 | struct queue_entry *entry = (struct queue_entry *)urb->context; | ||
402 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | ||
403 | |||
404 | if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) | ||
405 | return; | ||
406 | |||
407 | /* | ||
408 | * Report the frame as DMA done | ||
409 | */ | ||
410 | rt2x00lib_dmadone(entry); | ||
411 | |||
412 | /* | ||
413 | * Check if the received data is simply too small | ||
414 | * to be actually valid, or if the urb is signaling | ||
415 | * a problem. | ||
416 | */ | ||
417 | if (urb->actual_length < entry->queue->desc_size || urb->status) | ||
418 | set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); | ||
419 | |||
420 | /* | ||
421 | * Schedule the delayed work for reading the RX status | ||
422 | * from the device. | ||
423 | */ | ||
424 | ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work); | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * Radio handlers | 445 | * Radio handlers |
429 | */ | 446 | */ |
430 | void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) | 447 | void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) |
431 | { | 448 | { |
432 | rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0, | 449 | rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0, |
433 | REGISTER_TIMEOUT); | 450 | REGISTER_TIMEOUT); |
434 | |||
435 | rt2x00dev->ops->lib->stop_queue(rt2x00dev->rx); | ||
436 | } | 451 | } |
437 | EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); | 452 | EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); |
438 | 453 | ||
@@ -441,31 +456,10 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); | |||
441 | */ | 456 | */ |
442 | void rt2x00usb_clear_entry(struct queue_entry *entry) | 457 | void rt2x00usb_clear_entry(struct queue_entry *entry) |
443 | { | 458 | { |
444 | struct usb_device *usb_dev = | ||
445 | to_usb_device_intf(entry->queue->rt2x00dev->dev); | ||
446 | struct queue_entry_priv_usb *entry_priv = entry->priv_data; | ||
447 | int pipe; | ||
448 | int status; | ||
449 | |||
450 | entry->flags = 0; | 459 | entry->flags = 0; |
451 | 460 | ||
452 | if (entry->queue->qid == QID_RX) { | 461 | if (entry->queue->qid == QID_RX) |
453 | pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint); | 462 | rt2x00usb_kick_rx_entry(entry); |
454 | usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe, | ||
455 | entry->skb->data, entry->skb->len, | ||
456 | rt2x00usb_interrupt_rxdone, entry); | ||
457 | |||
458 | set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); | ||
459 | |||
460 | status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC); | ||
461 | if (status) { | ||
462 | if (status == -ENODEV) | ||
463 | clear_bit(DEVICE_STATE_PRESENT, | ||
464 | &entry->queue->rt2x00dev->flags); | ||
465 | set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); | ||
466 | rt2x00lib_dmadone(entry); | ||
467 | } | ||
468 | } | ||
469 | } | 463 | } |
470 | EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); | 464 | EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); |
471 | 465 | ||