carl9170 firmware: double check if unlinked desc matches head desc
[carl9170fw.git] / carlfw / src / wlan.c
index cc2b917d35e30e6c07a58499c5769ec1324d9bc3..a7c805b588908267541bd994f6c878a0abea16c2 100644 (file)
@@ -235,13 +235,19 @@ static inline bool same_aggr(struct ieee80211_hdr *a, struct ieee80211_hdr *b)
        return (get_tid(a) == get_tid(b)) || same_hdr(a, b);
 }
 
+static void wlan_tx_ampdu_reset(unsigned int qidx)
+{
+       fw.wlan.ampdu_prev[qidx] = NULL;
+}
+
 static void wlan_tx_ampdu_end(unsigned int qidx)
 {
        struct carl9170_tx_superframe *ht_prev = fw.wlan.ampdu_prev[qidx];
 
-       fw.wlan.ampdu_prev[qidx] = NULL;
        if (ht_prev)
                ht_prev->f.hdr.mac.ba_end = 1;
+
+       wlan_tx_ampdu_reset(qidx);
 }
 
 static void wlan_tx_ampdu(struct carl9170_tx_superframe *super)
@@ -249,16 +255,16 @@ static void wlan_tx_ampdu(struct carl9170_tx_superframe *super)
        unsigned int qidx = super->s.queue;
        struct carl9170_tx_superframe *ht_prev = fw.wlan.ampdu_prev[qidx];
 
-       if (!super->f.hdr.mac.ampdu) {
-               wlan_tx_ampdu_end(qidx);
-       } else {
-               fw.wlan.ampdu_prev[qidx] = super;
-
+       if (super->f.hdr.mac.ampdu) {
                if (ht_prev &&
                    !same_aggr(&super->f.data.i3e, &ht_prev->f.data.i3e))
                        ht_prev->f.hdr.mac.ba_end = 1;
                else
                        super->f.hdr.mac.ba_end = 0;
+
+               fw.wlan.ampdu_prev[qidx] = super;
+       } else {
+               wlan_tx_ampdu_end(qidx);
        }
 }
 
@@ -337,8 +343,6 @@ static void _wlan_tx(struct dma_desc *desc)
                            get(AR9170_MAC_REG_AMPDU_FACTOR),
                            8 << super->s.ampdu_factor));
        }
-
-       __wlan_tx(desc);
 }
 
 /* propagate transmission status back to the driver */
@@ -404,7 +408,11 @@ static bool wlan_tx_status(struct dma_queue *queue,
                                 * be aware of this so the frames don't get lost.
                                 */
 
+#ifndef CONFIG_CARL9170FW_DEBUG
                                dma_unlink_head(queue);
+#else /* CONFIG_CARL9170FW_DEBUG */
+                               BUG_ON(dma_unlink_head(queue) != desc);
+#endif /* CONFIG_CARL9170FW_DEBUG */
                                dma_put(&fw.wlan.tx_retry, desc);
                                return true;
                        }
@@ -414,7 +422,11 @@ static bool wlan_tx_status(struct dma_queue *queue,
                }
        }
 
+#ifndef CONFIG_CARL9170FW_DEBUG
        dma_unlink_head(queue);
+#else /* CONFIG_CARL9170FW_DEBUG */
+       BUG_ON(dma_unlink_head(queue) != desc);
+#endif /* CONFIG_CARL9170FW_DEBUG */
        if (txfail) {
                /*
                 * Issue the queue bump,
@@ -463,6 +475,8 @@ static void handle_tx_completion(void)
                        }
                }
 
+               wlan_tx_ampdu_reset(i);
+
                for_each_desc(desc, &fw.wlan.tx_retry)
                        __wlan_tx(desc);
 
@@ -490,6 +504,7 @@ void __hot wlan_tx(struct dma_desc *desc)
 #endif /* CONFIG_CARL9170FW_CAB_QUEUE */
 
        _wlan_tx(desc);
+       __wlan_tx(desc);
        wlan_trigger(BIT(super->s.queue));
 }
 
@@ -698,12 +713,10 @@ static unsigned int wlan_rx_filter(struct dma_desc *desc)
                rx_filter |= CARL9170_RX_FILTER_MGMT;
        }
 
-#ifdef CONFIG_CARL9170FW_WOL
        if (unlikely(fw.suspend_mode == CARL9170_HOST_SUSPENDED)) {
                wol_rx(rx_filter, hdr, min(data_len,
                        (unsigned int)AR9170_BLOCK_SIZE));
        }
-#endif /* CONFIG_CARL9170FW_WOL */
 
 #undef AR9170_RX_ERROR_BAD
 
@@ -753,6 +766,7 @@ void wlan_cab_flush_queue(const unsigned int vif)
 
                /* ready to roll! */
                _wlan_tx(desc);
+               __wlan_tx(desc);
                wlan_trigger(BIT(super->s.queue));
        }
 }