aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2012-05-18 00:46:38 -0400
committerLuciano Coelho <coelho@ti.com>2012-06-06 12:28:05 -0400
commit6639611467f34038aa63c5cb9f8d9e48171d6022 (patch)
tree22a03e2ce7cf2eaf53d2dba1705c496297abf30e /drivers
parent32bb2c03f990d015c0fec67e9134ea8625aaf784 (diff)
wlcore: add stop reason bitmap for waking/starting queues
Allow the driver to wake/stop the queues for multiple reasons. A queue is started when no stop-reasons exist. Convert all wake/stop queue calls to use the new API. Before, a stopped queue was almost synonymous a high-watermark on Tx. Remove a bit of code in wl12xx_tx_reset() that relied on it. Internal packets arriving from mac80211 are also discarded when a queue is stopped. A notable exception to this is the watermark reason, which is a "soft"-stop reason. We allow traffic to gradually come to a halt, but we don't mind spurious packets here and there. This is merely a flow regulation mechanism. Based on a similar patch by Eliad Peller <eliadWizery.com>. Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c21
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c109
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.h21
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h2
4 files changed, 132 insertions, 21 deletions
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 0f25d4eea037..bbab19a1ce8a 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -865,7 +865,7 @@ static void wl1271_recovery_work(struct work_struct *work)
865 } 865 }
866 866
867 /* Prevent spurious TX during FW restart */ 867 /* Prevent spurious TX during FW restart */
868 ieee80211_stop_queues(wl->hw); 868 wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
869 869
870 if (wl->sched_scanning) { 870 if (wl->sched_scanning) {
871 ieee80211_sched_scan_stopped(wl->hw); 871 ieee80211_sched_scan_stopped(wl->hw);
@@ -890,7 +890,7 @@ static void wl1271_recovery_work(struct work_struct *work)
890 * Its safe to enable TX now - the queues are stopped after a request 890 * Its safe to enable TX now - the queues are stopped after a request
891 * to restart the HW. 891 * to restart the HW.
892 */ 892 */
893 ieee80211_wake_queues(wl->hw); 893 wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
894 return; 894 return;
895out_unlock: 895out_unlock:
896 mutex_unlock(&wl->mutex); 896 mutex_unlock(&wl->mutex);
@@ -1107,9 +1107,16 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1107 1107
1108 spin_lock_irqsave(&wl->wl_lock, flags); 1108 spin_lock_irqsave(&wl->wl_lock, flags);
1109 1109
1110 /* queue the packet */ 1110 /*
1111 * drop the packet if the link is invalid or the queue is stopped
1112 * for any reason but watermark. Watermark is a "soft"-stop so we
1113 * allow these packets through.
1114 */
1111 if (hlid == WL12XX_INVALID_LINK_ID || 1115 if (hlid == WL12XX_INVALID_LINK_ID ||
1112 (wlvif && !test_bit(hlid, wlvif->links_map))) { 1116 (wlvif && !test_bit(hlid, wlvif->links_map)) ||
1117 (wlcore_is_queue_stopped(wl, q) &&
1118 !wlcore_is_queue_stopped_by_reason(wl, q,
1119 WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
1113 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q); 1120 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1114 ieee80211_free_txskb(hw, skb); 1121 ieee80211_free_txskb(hw, skb);
1115 goto out; 1122 goto out;
@@ -1127,8 +1134,8 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1127 */ 1134 */
1128 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) { 1135 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1129 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); 1136 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1130 ieee80211_stop_queue(wl->hw, mapping); 1137 wlcore_stop_queue_locked(wl, q,
1131 set_bit(q, &wl->stopped_queues_map); 1138 WLCORE_QUEUE_STOP_REASON_WATERMARK);
1132 } 1139 }
1133 1140
1134 /* 1141 /*
@@ -1711,7 +1718,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
1711 cancel_delayed_work_sync(&wl->connection_loss_work); 1718 cancel_delayed_work_sync(&wl->connection_loss_work);
1712 1719
1713 /* let's notify MAC80211 about the remaining pending TX frames */ 1720 /* let's notify MAC80211 about the remaining pending TX frames */
1714 wl12xx_tx_reset(wl, true); 1721 wl12xx_tx_reset(wl);
1715 mutex_lock(&wl->mutex); 1722 mutex_lock(&wl->mutex);
1716 1723
1717 wl1271_power_off(wl); 1724 wl1271_power_off(wl);
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index 0949ab1f5972..f68567b1524c 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -443,18 +443,15 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
443 443
444void wl1271_handle_tx_low_watermark(struct wl1271 *wl) 444void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
445{ 445{
446 unsigned long flags;
447 int i; 446 int i;
448 447
449 for (i = 0; i < NUM_TX_QUEUES; i++) { 448 for (i = 0; i < NUM_TX_QUEUES; i++) {
450 if (test_bit(i, &wl->stopped_queues_map) && 449 if (wlcore_is_queue_stopped_by_reason(wl, i,
450 WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
451 wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) { 451 wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) {
452 /* firmware buffer has space, restart queues */ 452 /* firmware buffer has space, restart queues */
453 spin_lock_irqsave(&wl->wl_lock, flags); 453 wlcore_wake_queue(wl, i,
454 ieee80211_wake_queue(wl->hw, 454 WLCORE_QUEUE_STOP_REASON_WATERMARK);
455 wl1271_tx_get_mac80211_queue(i));
456 clear_bit(i, &wl->stopped_queues_map);
457 spin_unlock_irqrestore(&wl->wl_lock, flags);
458 } 455 }
459 } 456 }
460} 457}
@@ -963,7 +960,7 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
963 960
964} 961}
965/* caller must hold wl->mutex and TX must be stopped */ 962/* caller must hold wl->mutex and TX must be stopped */
966void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues) 963void wl12xx_tx_reset(struct wl1271 *wl)
967{ 964{
968 int i; 965 int i;
969 struct sk_buff *skb; 966 struct sk_buff *skb;
@@ -978,15 +975,12 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
978 wl->tx_queue_count[i] = 0; 975 wl->tx_queue_count[i] = 0;
979 } 976 }
980 977
981 wl->stopped_queues_map = 0;
982
983 /* 978 /*
984 * Make sure the driver is at a consistent state, in case this 979 * Make sure the driver is at a consistent state, in case this
985 * function is called from a context other than interface removal. 980 * function is called from a context other than interface removal.
986 * This call will always wake the TX queues. 981 * This call will always wake the TX queues.
987 */ 982 */
988 if (reset_tx_queues) 983 wl1271_handle_tx_low_watermark(wl);
989 wl1271_handle_tx_low_watermark(wl);
990 984
991 for (i = 0; i < wl->num_tx_desc; i++) { 985 for (i = 0; i < wl->num_tx_desc; i++) {
992 if (wl->tx_frames[i] == NULL) 986 if (wl->tx_frames[i] == NULL)
@@ -1060,3 +1054,94 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
1060 1054
1061 return BIT(__ffs(rate_set)); 1055 return BIT(__ffs(rate_set));
1062} 1056}
1057
1058void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
1059 enum wlcore_queue_stop_reason reason)
1060{
1061 bool stopped = !!wl->queue_stop_reasons[queue];
1062
1063 /* queue should not be stopped for this reason */
1064 WARN_ON(test_and_set_bit(reason, &wl->queue_stop_reasons[queue]));
1065
1066 if (stopped)
1067 return;
1068
1069 ieee80211_stop_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
1070}
1071
1072void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
1073 enum wlcore_queue_stop_reason reason)
1074{
1075 unsigned long flags;
1076
1077 spin_lock_irqsave(&wl->wl_lock, flags);
1078 wlcore_stop_queue_locked(wl, queue, reason);
1079 spin_unlock_irqrestore(&wl->wl_lock, flags);
1080}
1081
1082void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
1083 enum wlcore_queue_stop_reason reason)
1084{
1085 unsigned long flags;
1086
1087 spin_lock_irqsave(&wl->wl_lock, flags);
1088
1089 /* queue should not be clear for this reason */
1090 WARN_ON(!test_and_clear_bit(reason, &wl->queue_stop_reasons[queue]));
1091
1092 if (wl->queue_stop_reasons[queue])
1093 goto out;
1094
1095 ieee80211_wake_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
1096
1097out:
1098 spin_unlock_irqrestore(&wl->wl_lock, flags);
1099}
1100
1101void wlcore_stop_queues(struct wl1271 *wl,
1102 enum wlcore_queue_stop_reason reason)
1103{
1104 int i;
1105
1106 for (i = 0; i < NUM_TX_QUEUES; i++)
1107 wlcore_stop_queue(wl, i, reason);
1108}
1109
1110void wlcore_wake_queues(struct wl1271 *wl,
1111 enum wlcore_queue_stop_reason reason)
1112{
1113 int i;
1114
1115 for (i = 0; i < NUM_TX_QUEUES; i++)
1116 wlcore_wake_queue(wl, i, reason);
1117}
1118
1119void wlcore_reset_stopped_queues(struct wl1271 *wl)
1120{
1121 int i;
1122 unsigned long flags;
1123
1124 spin_lock_irqsave(&wl->wl_lock, flags);
1125
1126 for (i = 0; i < NUM_TX_QUEUES; i++) {
1127 if (!wl->queue_stop_reasons[i])
1128 continue;
1129
1130 wl->queue_stop_reasons[i] = 0;
1131 ieee80211_wake_queue(wl->hw,
1132 wl1271_tx_get_mac80211_queue(i));
1133 }
1134
1135 spin_unlock_irqrestore(&wl->wl_lock, flags);
1136}
1137
1138bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
1139 enum wlcore_queue_stop_reason reason)
1140{
1141 return test_bit(reason, &wl->queue_stop_reasons[queue]);
1142}
1143
1144bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue)
1145{
1146 return !!wl->queue_stop_reasons[queue];
1147}
diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h
index e24c436bf65f..6bf695681762 100644
--- a/drivers/net/wireless/ti/wlcore/tx.h
+++ b/drivers/net/wireless/ti/wlcore/tx.h
@@ -184,6 +184,11 @@ struct wl1271_tx_hw_res_if {
184 struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN]; 184 struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
185} __packed; 185} __packed;
186 186
187enum wlcore_queue_stop_reason {
188 WLCORE_QUEUE_STOP_REASON_WATERMARK,
189 WLCORE_QUEUE_STOP_REASON_FW_RESTART,
190};
191
187static inline int wl1271_tx_get_queue(int queue) 192static inline int wl1271_tx_get_queue(int queue)
188{ 193{
189 switch (queue) { 194 switch (queue) {
@@ -230,7 +235,7 @@ void wl1271_tx_work(struct work_struct *work);
230void wl1271_tx_work_locked(struct wl1271 *wl); 235void wl1271_tx_work_locked(struct wl1271 *wl);
231void wl1271_tx_complete(struct wl1271 *wl); 236void wl1271_tx_complete(struct wl1271 *wl);
232void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif); 237void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
233void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues); 238void wl12xx_tx_reset(struct wl1271 *wl);
234void wl1271_tx_flush(struct wl1271 *wl); 239void wl1271_tx_flush(struct wl1271 *wl);
235u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band); 240u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band);
236u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, 241u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
@@ -247,6 +252,20 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
247unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, 252unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
248 unsigned int packet_length); 253 unsigned int packet_length);
249void wl1271_free_tx_id(struct wl1271 *wl, int id); 254void wl1271_free_tx_id(struct wl1271 *wl, int id);
255void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
256 enum wlcore_queue_stop_reason reason);
257void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
258 enum wlcore_queue_stop_reason reason);
259void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
260 enum wlcore_queue_stop_reason reason);
261void wlcore_stop_queues(struct wl1271 *wl,
262 enum wlcore_queue_stop_reason reason);
263void wlcore_wake_queues(struct wl1271 *wl,
264 enum wlcore_queue_stop_reason reason);
265void wlcore_reset_stopped_queues(struct wl1271 *wl);
266bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
267 enum wlcore_queue_stop_reason reason);
268bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue);
250 269
251/* from main.c */ 270/* from main.c */
252void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); 271void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 5274ace6c8e4..681054331fd2 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -209,7 +209,7 @@ struct wl1271 {
209 209
210 /* Frames scheduled for transmission, not handled yet */ 210 /* Frames scheduled for transmission, not handled yet */
211 int tx_queue_count[NUM_TX_QUEUES]; 211 int tx_queue_count[NUM_TX_QUEUES];
212 long stopped_queues_map; 212 unsigned long queue_stop_reasons[NUM_TX_QUEUES];
213 213
214 /* Frames received, not handled yet by mac80211 */ 214 /* Frames received, not handled yet by mac80211 */
215 struct sk_buff_head deferred_rx_queue; 215 struct sk_buff_head deferred_rx_queue;