aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2012-05-18 00:46:39 -0400
committerLuciano Coelho <coelho@ti.com>2012-06-06 12:28:05 -0400
commit2c38849f4a247673c8203a569444042e32d82410 (patch)
tree86b41dd4670f9d1ffa9997cc43ca4565a5050c2b /drivers
parent6639611467f34038aa63c5cb9f8d9e48171d6022 (diff)
wlcore: stop queues on Tx flush
Stop network queues during Tx flush, and also drop other internal mac80211 packets (mgmt) that may arrive when the queues are stopped. When flush is done all driver queues are clear, forcefully if needed. Protect the Tx flush operation with a new mutex, to prevent concurrency that can mess us queue state. Based on a patch by Eliad Peller <eliad@wizery.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.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c11
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.h1
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h3
4 files changed, 15 insertions, 1 deletions
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index bbab19a1ce8a..d81c86cbbf71 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -5148,6 +5148,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
5148 wl->state = WL1271_STATE_OFF; 5148 wl->state = WL1271_STATE_OFF;
5149 wl->fw_type = WL12XX_FW_TYPE_NONE; 5149 wl->fw_type = WL12XX_FW_TYPE_NONE;
5150 mutex_init(&wl->mutex); 5150 mutex_init(&wl->mutex);
5151 mutex_init(&wl->flush_mutex);
5151 5152
5152 order = get_order(WL1271_AGGR_BUFFER_SIZE); 5153 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5153 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); 5154 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index f68567b1524c..78bf1b9208a9 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -1024,6 +1024,11 @@ void wl1271_tx_flush(struct wl1271 *wl)
1024 int i; 1024 int i;
1025 timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); 1025 timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
1026 1026
1027 /* only one flush should be in progress, for consistent queue state */
1028 mutex_lock(&wl->flush_mutex);
1029
1030 wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
1031
1027 while (!time_after(jiffies, timeout)) { 1032 while (!time_after(jiffies, timeout)) {
1028 mutex_lock(&wl->mutex); 1033 mutex_lock(&wl->mutex);
1029 wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", 1034 wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d",
@@ -1032,7 +1037,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
1032 if ((wl->tx_frames_cnt == 0) && 1037 if ((wl->tx_frames_cnt == 0) &&
1033 (wl1271_tx_total_queue_count(wl) == 0)) { 1038 (wl1271_tx_total_queue_count(wl) == 0)) {
1034 mutex_unlock(&wl->mutex); 1039 mutex_unlock(&wl->mutex);
1035 return; 1040 goto out;
1036 } 1041 }
1037 mutex_unlock(&wl->mutex); 1042 mutex_unlock(&wl->mutex);
1038 msleep(1); 1043 msleep(1);
@@ -1045,6 +1050,10 @@ void wl1271_tx_flush(struct wl1271 *wl)
1045 for (i = 0; i < WL12XX_MAX_LINKS; i++) 1050 for (i = 0; i < WL12XX_MAX_LINKS; i++)
1046 wl1271_tx_reset_link_queues(wl, i); 1051 wl1271_tx_reset_link_queues(wl, i);
1047 mutex_unlock(&wl->mutex); 1052 mutex_unlock(&wl->mutex);
1053
1054out:
1055 wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
1056 mutex_unlock(&wl->flush_mutex);
1048} 1057}
1049 1058
1050u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) 1059u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h
index 6bf695681762..e058a55f533d 100644
--- a/drivers/net/wireless/ti/wlcore/tx.h
+++ b/drivers/net/wireless/ti/wlcore/tx.h
@@ -187,6 +187,7 @@ struct wl1271_tx_hw_res_if {
187enum wlcore_queue_stop_reason { 187enum wlcore_queue_stop_reason {
188 WLCORE_QUEUE_STOP_REASON_WATERMARK, 188 WLCORE_QUEUE_STOP_REASON_WATERMARK,
189 WLCORE_QUEUE_STOP_REASON_FW_RESTART, 189 WLCORE_QUEUE_STOP_REASON_FW_RESTART,
190 WLCORE_QUEUE_STOP_REASON_FLUSH,
190}; 191};
191 192
192static inline int wl1271_tx_get_queue(int queue) 193static inline int wl1271_tx_get_queue(int queue)
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 681054331fd2..99a061950a3a 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -378,6 +378,9 @@ struct wl1271 {
378 378
379 /* the current channel type */ 379 /* the current channel type */
380 enum nl80211_channel_type channel_type; 380 enum nl80211_channel_type channel_type;
381
382 /* mutex for protecting the tx_flush function */
383 struct mutex flush_mutex;
381}; 384};
382 385
383int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); 386int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);