Commit 2c38849f authored by Arik Nemtsov's avatar Arik Nemtsov Committed by Luciano Coelho

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: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent 66396114
...@@ -5148,6 +5148,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size) ...@@ -5148,6 +5148,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
wl->state = WL1271_STATE_OFF; wl->state = WL1271_STATE_OFF;
wl->fw_type = WL12XX_FW_TYPE_NONE; wl->fw_type = WL12XX_FW_TYPE_NONE;
mutex_init(&wl->mutex); mutex_init(&wl->mutex);
mutex_init(&wl->flush_mutex);
order = get_order(WL1271_AGGR_BUFFER_SIZE); order = get_order(WL1271_AGGR_BUFFER_SIZE);
wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
......
...@@ -1024,6 +1024,11 @@ void wl1271_tx_flush(struct wl1271 *wl) ...@@ -1024,6 +1024,11 @@ void wl1271_tx_flush(struct wl1271 *wl)
int i; int i;
timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
/* only one flush should be in progress, for consistent queue state */
mutex_lock(&wl->flush_mutex);
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
while (!time_after(jiffies, timeout)) { while (!time_after(jiffies, timeout)) {
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d",
...@@ -1032,7 +1037,7 @@ void wl1271_tx_flush(struct wl1271 *wl) ...@@ -1032,7 +1037,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
if ((wl->tx_frames_cnt == 0) && if ((wl->tx_frames_cnt == 0) &&
(wl1271_tx_total_queue_count(wl) == 0)) { (wl1271_tx_total_queue_count(wl) == 0)) {
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
return; goto out;
} }
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
msleep(1); msleep(1);
...@@ -1045,6 +1050,10 @@ void wl1271_tx_flush(struct wl1271 *wl) ...@@ -1045,6 +1050,10 @@ void wl1271_tx_flush(struct wl1271 *wl)
for (i = 0; i < WL12XX_MAX_LINKS; i++) for (i = 0; i < WL12XX_MAX_LINKS; i++)
wl1271_tx_reset_link_queues(wl, i); wl1271_tx_reset_link_queues(wl, i);
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
out:
wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
mutex_unlock(&wl->flush_mutex);
} }
u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
......
...@@ -187,6 +187,7 @@ struct wl1271_tx_hw_res_if { ...@@ -187,6 +187,7 @@ struct wl1271_tx_hw_res_if {
enum wlcore_queue_stop_reason { enum wlcore_queue_stop_reason {
WLCORE_QUEUE_STOP_REASON_WATERMARK, WLCORE_QUEUE_STOP_REASON_WATERMARK,
WLCORE_QUEUE_STOP_REASON_FW_RESTART, WLCORE_QUEUE_STOP_REASON_FW_RESTART,
WLCORE_QUEUE_STOP_REASON_FLUSH,
}; };
static inline int wl1271_tx_get_queue(int queue) static inline int wl1271_tx_get_queue(int queue)
......
...@@ -378,6 +378,9 @@ struct wl1271 { ...@@ -378,6 +378,9 @@ struct wl1271 {
/* the current channel type */ /* the current channel type */
enum nl80211_channel_type channel_type; enum nl80211_channel_type channel_type;
/* mutex for protecting the tx_flush function */
struct mutex flush_mutex;
}; };
int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment