wl1251: do tx as soon as there's space
authorGrazvydas Ignotas <notasas@gmail.com>
Mon, 16 Feb 2015 20:43:37 +0000 (22:43 +0200)
committerGrazvydas Ignotas <notasas@gmail.com>
Fri, 20 Feb 2015 22:05:31 +0000 (00:05 +0200)
This way firmware will get tx packet without having to wait for rx
of other irqs to be processed first.
(not sure about improvement, if any, from this patch, as always it's
too unstable/inconsistent to make a proper measurement)

drivers/net/wireless/wl1251/main.c
drivers/net/wireless/wl1251/tx.c
drivers/net/wireless/wl1251/tx.h

index e6a1475..42b8df5 100644 (file)
@@ -279,9 +279,18 @@ irqreturn_t wl1251_irq(int irq, void *cookie)
                        goto out_sleep;
                }
 
+               if (intr & WL1251_ACX_INTR_TX_RESULT) {
+                       wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
+                       wl1251_tx_complete(wl);
+               }
+
                if (intr & WL1251_ACX_INTR_RX0_DATA) {
                        wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
                        wl1251_rx(wl);
+
+                       if ((intr & WL1251_ACX_INTR_RX1_DATA)
+                           && skb_queue_len(&wl->tx_queue) > 0)
+                               wl1251_tx_work_unlocked(wl, false);
                }
 
                if (intr & WL1251_ACX_INTR_RX1_DATA) {
@@ -289,11 +298,6 @@ irqreturn_t wl1251_irq(int irq, void *cookie)
                        wl1251_rx(wl);
                }
 
-               if (intr & WL1251_ACX_INTR_TX_RESULT) {
-                       wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
-                       wl1251_tx_complete(wl);
-               }
-
                if (intr & WL1251_ACX_INTR_EVENT_A) {
                        wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_A");
                        wl1251_event_handle(wl, 0);
@@ -308,21 +312,8 @@ irqreturn_t wl1251_irq(int irq, void *cookie)
                        wl1251_debug(DEBUG_IRQ,
                                     "WL1251_ACX_INTR_INIT_COMPLETE");
 
-               while (skb_queue_len(&wl->tx_queue) > 0
-                      && wl1251_tx_path_status(wl) == 0) {
-
-                       struct sk_buff *skb = skb_dequeue(&wl->tx_queue);
-                       if (skb == NULL)
-                               goto out_sleep;
-
-                       ret = wl1251_tx_frame(wl, skb);
-                       if (ret == -EBUSY) {
-                               skb_queue_head(&wl->tx_queue, skb);
-                               break;
-                       } else if (ret < 0) {
-                               dev_kfree_skb(skb);
-                       }
-               }
+               if (skb_queue_len(&wl->tx_queue) > 0)
+                       wl1251_tx_work_unlocked(wl, false);
 
                if (--ctr == 0)
                        break;
index 90379a8..421afe4 100644 (file)
@@ -345,20 +345,17 @@ int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
        return ret;
 }
 
-void wl1251_tx_work(struct work_struct *work)
+void wl1251_tx_work_unlocked(struct wl1251 *wl, bool need_pm)
 {
-       struct wl1251 *wl = container_of(work, struct wl1251, tx_work);
        struct sk_buff *skb;
        bool woken_up = false;
        int ret;
 
-       mutex_lock(&wl->mutex);
-
        if (unlikely(wl->state == WL1251_STATE_OFF))
                goto out;
 
        while ((skb = skb_dequeue(&wl->tx_queue))) {
-               if (!woken_up) {
+               if (need_pm && !woken_up) {
                        ret = wl1251_ps_elp_wakeup(wl);
                        if (ret < 0)
                                goto out;
@@ -378,7 +375,14 @@ void wl1251_tx_work(struct work_struct *work)
 out:
        if (woken_up)
                wl1251_ps_elp_sleep(wl);
+}
 
+void wl1251_tx_work(struct work_struct *work)
+{
+       struct wl1251 *wl = container_of(work, struct wl1251, tx_work);
+
+       mutex_lock(&wl->mutex);
+       wl1251_tx_work_unlocked(wl, true);
        mutex_unlock(&wl->mutex);
 }
 
@@ -491,24 +495,6 @@ void wl1251_tx_complete(struct wl1251 *wl)
                }
        }
 
-       queue_len = skb_queue_len(&wl->tx_queue);
-
-       if ((num_complete > 0) && (queue_len > 0)) {
-               /* firmware buffer has space, reschedule tx_work */
-               wl1251_debug(DEBUG_TX, "tx_complete: reschedule tx_work");
-               ieee80211_queue_work(wl->hw, &wl->tx_work);
-       }
-
-       if (wl->tx_queue_stopped &&
-           queue_len <= WL1251_TX_QUEUE_LOW_WATERMARK) {
-               /* tx_queue has space, restart queues */
-               wl1251_debug(DEBUG_TX, "tx_complete: waking queues");
-               spin_lock_irqsave(&wl->wl_lock, flags);
-               ieee80211_wake_queues(wl->hw);
-               wl->tx_queue_stopped = false;
-               spin_unlock_irqrestore(&wl->wl_lock, flags);
-       }
-
        /* Every completed frame needs to be acknowledged */
        if (num_complete) {
                /*
@@ -557,6 +543,29 @@ void wl1251_tx_complete(struct wl1251 *wl)
        }
 
        wl->next_tx_complete = result_index;
+
+       queue_len = skb_queue_len(&wl->tx_queue);
+       if (queue_len > 0) {
+               /* avoid stalling tx */
+               wl1251_tx_work_unlocked(wl, false);
+               queue_len = skb_queue_len(&wl->tx_queue);
+       }
+
+       if (queue_len > 0) {
+               /* still something to send? Schedule for later */
+               wl1251_debug(DEBUG_TX, "tx_complete: reschedule tx_work");
+               ieee80211_queue_work(wl->hw, &wl->tx_work);
+       }
+
+       if (wl->tx_queue_stopped &&
+           queue_len <= WL1251_TX_QUEUE_LOW_WATERMARK) {
+               /* tx_queue has space, restart queues */
+               wl1251_debug(DEBUG_TX, "tx_complete: waking queues");
+               spin_lock_irqsave(&wl->wl_lock, flags);
+               ieee80211_wake_queues(wl->hw);
+               wl->tx_queue_stopped = false;
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
+       }
 }
 
 /* caller must hold wl->mutex */
index da5b6ec..4541a58 100644 (file)
@@ -224,6 +224,7 @@ static inline int wl1251_tx_get_queue(int queue)
        }
 }
 
+void wl1251_tx_work_unlocked(struct wl1251 *wl, bool need_pm);
 void wl1251_tx_work(struct work_struct *work);
 void wl1251_tx_complete(struct wl1251 *wl);
 void wl1251_tx_flush(struct wl1251 *wl);