|
@@ -212,6 +212,20 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
|
|
|
return enabled_rates;
|
|
|
}
|
|
|
|
|
|
+static void handle_tx_low_watermark(struct wl1271 *wl)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) &&
|
|
|
+ skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) {
|
|
|
+ /* firmware buffer has space, restart queues */
|
|
|
+ spin_lock_irqsave(&wl->wl_lock, flags);
|
|
|
+ ieee80211_wake_queues(wl->hw);
|
|
|
+ clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
|
|
|
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void wl1271_tx_work_locked(struct wl1271 *wl)
|
|
|
{
|
|
|
struct sk_buff *skb;
|
|
@@ -225,6 +239,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
|
|
if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED,
|
|
|
&wl->flags))) {
|
|
|
unsigned long flags;
|
|
|
+
|
|
|
spin_lock_irqsave(&wl->wl_lock, flags);
|
|
|
sta_rates = wl->sta_rate_set;
|
|
|
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
|
@@ -285,6 +300,7 @@ out_ack:
|
|
|
if (sent_packets) {
|
|
|
/* interrupt the firmware with the new packets */
|
|
|
wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
|
|
|
+ handle_tx_low_watermark(wl);
|
|
|
}
|
|
|
|
|
|
out:
|
|
@@ -399,19 +415,6 @@ void wl1271_tx_complete(struct wl1271 *wl)
|
|
|
|
|
|
wl->tx_results_count++;
|
|
|
}
|
|
|
-
|
|
|
- if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) &&
|
|
|
- skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) {
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- /* firmware buffer has space, restart queues */
|
|
|
- wl1271_debug(DEBUG_TX, "tx_complete: waking queues");
|
|
|
- spin_lock_irqsave(&wl->wl_lock, flags);
|
|
|
- ieee80211_wake_queues(wl->hw);
|
|
|
- clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
|
|
|
- spin_unlock_irqrestore(&wl->wl_lock, flags);
|
|
|
- ieee80211_queue_work(wl->hw, &wl->tx_work);
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
/* caller must hold wl->mutex */
|
|
@@ -426,6 +429,12 @@ void wl1271_tx_reset(struct wl1271 *wl)
|
|
|
ieee80211_tx_status(wl->hw, skb);
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Make sure the driver is at a consistent state, in case this
|
|
|
+ * function is called from a context other than interface removal.
|
|
|
+ */
|
|
|
+ handle_tx_low_watermark(wl);
|
|
|
+
|
|
|
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
|
|
|
if (wl->tx_frames[i] != NULL) {
|
|
|
skb = wl->tx_frames[i];
|