diff options
author | Jérôme Pouiller <jerome.pouiller@silabs.com> | 2020-04-01 13:04:01 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-04-13 08:55:37 +0200 |
commit | 4c6b3837c6dc0d9e5f9ec910da2e36349beea733 (patch) | |
tree | 7298ea6c467be03e12cc55377c59ecf7b92f1297 /drivers/staging/wfx/data_tx.c | |
parent | staging: wfx: relocate wfx_skb_dtor() prior its callers (diff) | |
download | linux-dev-4c6b3837c6dc0d9e5f9ec910da2e36349beea733.tar.xz linux-dev-4c6b3837c6dc0d9e5f9ec910da2e36349beea733.zip |
staging: wfx: repair wfx_flush()
Until now, wfx_flush() flushed queue for while device instead of only
the queue of the intended vif. It sometime failed with a timeout, but
this error was not reported.
Moreover, if the device was frozen, wfx_flush didn't do anything and it
results a potential warning (and maybe a resource leak) when the frozen
device was unregistered.
We can also notice that wfx_tx_queues_wait_empty_vif() did only exist to
work around the broken feature of wfx_flush().
This patch repair wfx_flush() and therefore drop
wfx_tx_queues_wait_empty_vif().
Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
Link: https://lore.kernel.org/r/20200401110405.80282-29-Jerome.Pouiller@silabs.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/wfx/data_tx.c')
-rw-r--r-- | drivers/staging/wfx/data_tx.c | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c index ec95518c9167..1d9a8089f3d3 100644 --- a/drivers/staging/wfx/data_tx.c +++ b/drivers/staging/wfx/data_tx.c @@ -524,7 +524,7 @@ static void wfx_notify_buffered_tx(struct wfx_vif *wvif, struct sk_buff *skb) rcu_read_unlock(); } -void wfx_skb_dtor(struct wfx_dev *wdev, struct sk_buff *skb) +static void wfx_skb_dtor(struct wfx_dev *wdev, struct sk_buff *skb) { struct hif_msg *hif = (struct hif_msg *)skb->data; struct hif_req_tx *req = (struct hif_req_tx *)hif->body; @@ -626,4 +626,36 @@ void wfx_tx_confirm_cb(struct wfx_vif *wvif, const struct hif_cnf_tx *arg) wfx_skb_dtor(wvif->wdev, skb); } +void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct wfx_dev *wdev = hw->priv; + struct sk_buff_head dropped; + struct wfx_queue *queue; + struct sk_buff *skb; + int vif_id = -1; + int i; + + if (vif) + vif_id = ((struct wfx_vif *)vif->drv_priv)->id; + skb_queue_head_init(&dropped); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (!(BIT(i) & queues)) + continue; + queue = &wdev->tx_queue[i]; + if (drop) + wfx_tx_queue_drop(wdev, queue, vif_id, &dropped); + if (wdev->chip_frozen) + continue; + if (wait_event_timeout(wdev->tx_dequeue, + wfx_tx_queue_empty(wdev, queue, vif_id), + msecs_to_jiffies(1000)) <= 0) + dev_warn(wdev->dev, "frames queued while flushing tx queues?"); + } + wfx_tx_flush(wdev); + if (wdev->chip_frozen) + wfx_pending_drop(wdev, &dropped); + while ((skb = skb_dequeue(&dropped)) != NULL) + wfx_skb_dtor(wdev, skb); +} |