wlcore: stop queues on Tx flush
authorArik Nemtsov <arik@wizery.com>
Fri, 18 May 2012 04:46:39 +0000 (07:46 +0300)
committerLuciano Coelho <coelho@ti.com>
Wed, 6 Jun 2012 16:28:05 +0000 (19:28 +0300)
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>
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/tx.c
drivers/net/wireless/ti/wlcore/tx.h
drivers/net/wireless/ti/wlcore/wlcore.h

index bbab19a1ce8add34ed09e943d88701af77068382..d81c86cbbf71417fb05aee591f31ede19849eb73 100644 (file)
@@ -5148,6 +5148,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
        wl->state = WL1271_STATE_OFF;
        wl->fw_type = WL12XX_FW_TYPE_NONE;
        mutex_init(&wl->mutex);
+       mutex_init(&wl->flush_mutex);
 
        order = get_order(WL1271_AGGR_BUFFER_SIZE);
        wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
index f68567b1524c7166344949a9b226fc3d0c40ec3c..78bf1b9208a908773b1d59bd0dec321969b2069e 100644 (file)
@@ -1024,6 +1024,11 @@ void wl1271_tx_flush(struct wl1271 *wl)
        int i;
        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)) {
                mutex_lock(&wl->mutex);
                wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d",
@@ -1032,7 +1037,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
                if ((wl->tx_frames_cnt == 0) &&
                    (wl1271_tx_total_queue_count(wl) == 0)) {
                        mutex_unlock(&wl->mutex);
-                       return;
+                       goto out;
                }
                mutex_unlock(&wl->mutex);
                msleep(1);
@@ -1045,6 +1050,10 @@ void wl1271_tx_flush(struct wl1271 *wl)
        for (i = 0; i < WL12XX_MAX_LINKS; i++)
                wl1271_tx_reset_link_queues(wl, i);
        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)
index 6bf695681762e813e475ca1d74e1f073989d0fb9..e058a55f533d8a8e93a3911bbb042a8d21094f5a 100644 (file)
@@ -187,6 +187,7 @@ struct wl1271_tx_hw_res_if {
 enum wlcore_queue_stop_reason {
        WLCORE_QUEUE_STOP_REASON_WATERMARK,
        WLCORE_QUEUE_STOP_REASON_FW_RESTART,
+       WLCORE_QUEUE_STOP_REASON_FLUSH,
 };
 
 static inline int wl1271_tx_get_queue(int queue)
index 681054331fd2df08156d577ad32e4adbffb4f150..99a061950a3a25779bf981c519db7b77702dedeb 100644 (file)
@@ -378,6 +378,9 @@ struct wl1271 {
 
        /* the current 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);