carl9170 firmware: drop failed frames faster
authorChristian Lamparter <chunkeey@googlemail.com>
Sat, 5 Mar 2011 22:48:07 +0000 (23:48 +0100)
committerChristian Lamparter <chunkeey@googlemail.com>
Thu, 10 Mar 2011 01:54:57 +0000 (02:54 +0100)
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
carlfw/include/carl9170.h
carlfw/include/wl.h
carlfw/src/hostif.c
carlfw/src/wlan.c

index 72bd6118a34029673d8d1946d0f9c59722f78b47..85ea1d2425bd5895915aff9525cb407a61f01bac 100644 (file)
@@ -100,8 +100,8 @@ struct firmware_context_struct {
                struct carl9170_tx_superframe *ampdu_prev[__AR9170_NUM_TX_QUEUES];
 
                /* Hardware DMA queue unstuck/fix detection */
-               unsigned int last_tx_desc_num[__AR9170_NUM_TX_QUEUES];
-               struct dma_desc *last_tx_desc[__AR9170_NUM_TX_QUEUES];
+               unsigned int last_super_num[__AR9170_NUM_TX_QUEUES];
+               struct carl9170_tx_superframe *last_super[__AR9170_NUM_TX_QUEUES];
                unsigned int mac_reset;
                unsigned int soft_int;
 
index 7428d1a28760901d293c9c06f6a49a7d7ecb9db7..fb9b09fcbc0a761b416fa3ab4cfa0a4e0e5e6a77 100644 (file)
@@ -210,6 +210,11 @@ static inline __inline struct carl9170_tx_superframe *get_super(struct dma_desc
                            f);
 }
 
+static inline __inline struct carl9170_tx_superframe *__get_super(struct dma_desc *desc)
+{
+       return DESC_PAYLOAD(desc);
+}
+
 static inline __inline void hide_super(struct dma_desc *desc)
 {
        desc->dataAddr = (uint8_t *)
@@ -253,6 +258,9 @@ void wlan_modify_beacon(const unsigned int vif,
                        const unsigned int bcn_addr,
                        const unsigned int bcn_len);
 
+void wlan_tx_complete(struct carl9170_tx_superframe *super,
+                      bool txs);
+
 static inline void wlan_prepare_wol(void)
 {
        /* set filter policy to: discard everything */
index 94c2d04f064cca3ce297843c6fa70dfd8a148c0f..0e7cbf2a23d572b614e095d6e65c5b2071c3b5a4 100644 (file)
@@ -30,7 +30,7 @@
 
 static bool length_check(struct dma_desc *desc)
 {
-       volatile struct carl9170_tx_superframe *super = DESC_PAYLOAD(desc);
+       volatile struct carl9170_tx_superframe *super = __get_super(desc);
 
        if (unlikely(desc->totalLen < sizeof(struct carl9170_tx_superdesc)))
                return false;
@@ -59,7 +59,7 @@ static void handle_download(void)
         * is _SW ( handle_download_exception )
         */
 
-       for_each_desc_bits(desc, &fw.pta.down_queue, AR9170_OWN_BITS_SE) {
+       for_each_desc_not_bits(desc, &fw.pta.down_queue, AR9170_OWN_BITS_HW) {
                if (unlikely((length_check(desc) == false))) {
                        /*
                         * There is no easy way of telling what was lost.
@@ -69,6 +69,7 @@ static void handle_download(void)
                         * timeout mechanism.
                         */
 
+                       wlan_tx_complete(__get_super(desc), false);
                        dma_reclaim(&fw.pta.down_queue, desc);
                        down_trigger();
                } else {
index ff074e3982ee3451c16ec73492e809e8c73b34ad..4e0feafa12615c96806ee5e52f2b73c79a0b369b 100644 (file)
@@ -156,8 +156,8 @@ static struct carl9170_tx_status *wlan_get_tx_status_buffer(void)
 }
 
 /* generate _aggregated_ tx_status for the host */
-static void wlan_tx_complete(struct carl9170_tx_superframe *super,
-                            bool txs)
+void wlan_tx_complete(struct carl9170_tx_superframe *super,
+                     bool txs)
 {
        struct carl9170_tx_status *status;
 
@@ -169,6 +169,7 @@ static void wlan_tx_complete(struct carl9170_tx_superframe *super,
         */
        status->cookie = super->s.cookie;
        status->queue = super->s.queue;
+       super->s.cookie = 0;
 
        /*
         * This field holds the number of tries of the rate in
@@ -364,7 +365,7 @@ static bool wlan_tx_status(struct dma_queue *queue,
        success = true;
 
        /* update hangcheck */
-       fw.wlan.last_tx_desc_num[qidx] = 0;
+       fw.wlan.last_super_num[qidx] = 0;
 
        if (!!(desc->ctrl & AR9170_CTRL_FAIL)) {
                txfail = !!(desc->ctrl & AR9170_CTRL_TXFAIL);
@@ -1095,6 +1096,12 @@ void handle_wlan(void)
 #undef HANDLER
 }
 
+enum {
+       CARL9170FW_TX_MAC_BUMP = 4,
+       CARL9170FW_TX_MAC_DEBUG = 6,
+       CARL9170FW_TX_MAC_RESET = 7,
+};
+
 static void wlan_check_hang(void)
 {
        struct dma_desc *desc;
@@ -1110,10 +1117,10 @@ static void wlan_check_hang(void)
                desc = get_wlan_txq_addr(i);
 
                /* Stuck frame detection */
-               if (unlikely(desc == fw.wlan.last_tx_desc[i])) {
-                       fw.wlan.last_tx_desc_num[i]++;
+               if (unlikely(DESC_PAYLOAD(desc) == fw.wlan.last_super[i])) {
+                       fw.wlan.last_super_num[i]++;
 
-                       if (unlikely(fw.wlan.last_tx_desc_num[i] > 6)) {
+                       if (unlikely(fw.wlan.last_super_num[i] >= CARL9170FW_TX_MAC_RESET)) {
                                /*
                                 * schedule MAC reset (aka OFF/ON => dead)
                                 *
@@ -1126,7 +1133,7 @@ static void wlan_check_hang(void)
                        }
 
 #ifdef CONFIG_CARL9170FW_DEBUG
-                       if (unlikely(fw.wlan.last_tx_desc_num[i] > 5)) {
+                       if (unlikely(fw.wlan.last_super_num[i] >= CARL9170FW_TX_MAC_DEBUG)) {
                                /*
                                 * Sigh, the queue is almost certainly
                                 * dead. Dump the queue content to the
@@ -1139,7 +1146,7 @@ static void wlan_check_hang(void)
 #endif /* CONFIG_CARL9170FW_DEBUG */
 
 #ifdef CONFIG_CARL9170FW_DMA_QUEUE_BUMP
-                       if (unlikely(fw.wlan.last_tx_desc_num[i] > 3)) {
+                       if (unlikely(fw.wlan.last_super_num[i] >= CARL9170FW_TX_MAC_BUMP)) {
                                /*
                                 * Hrrm, bump the queue a bit.
                                 * maybe this will get it going again.
@@ -1151,8 +1158,8 @@ static void wlan_check_hang(void)
 #endif /* CONFIG_CARL9170FW_DMA_QUEUE_BUMP */
                } else {
                        /* Nothing stuck */
-                       fw.wlan.last_tx_desc[i] = desc;
-                       fw.wlan.last_tx_desc_num[i] = 0;
+                       fw.wlan.last_super[i] = DESC_PAYLOAD(desc);
+                       fw.wlan.last_super_num[i] = 0;
                }
        }
 }
@@ -1258,6 +1265,29 @@ static void wlan_mac_reset(void)
 
                __for_each_desc_bits(iter, &fw.wlan.tx_queue[i], AR9170_OWN_BITS_SW);
 
+               /* kill the stuck frame */
+               if (!is_terminator(&fw.wlan.tx_queue[i], iter) &&
+                   fw.wlan.last_super_num[i] >= CARL9170FW_TX_MAC_RESET &&
+                   fw.wlan.last_super[i] == DESC_PAYLOAD(iter)) {
+                       struct carl9170_tx_superframe *super = get_super(iter);
+
+                       iter->status = AR9170_OWN_BITS_SW;
+                       /*
+                        * Mark the frame as failed.
+                        * The BAFAIL flag allows the frame to sail through
+                        * wlan_tx_status without much "unstuck" trouble.
+                        */
+                       iter->ctrl &= ~(AR9170_CTRL_FAIL);
+                       iter->ctrl |= AR9170_CTRL_BAFAIL;
+
+                       super->s.cnt = CARL9170_TX_MAX_RATE_TRIES;
+                       super->s.rix = CARL9170_TX_MAX_RETRY_RATES;
+
+                       fw.wlan.last_super_num[i] = 0;
+                       fw.wlan.last_super[i] = NULL;
+                       iter = iter->lastAddr->nextAddr;
+               }
+
                set_wlan_txq_dma_addr(i, (uint32_t) iter);
                if (!is_terminator(&fw.wlan.tx_queue[i], iter))
                        val |= BIT(i);