carl9170 firmware: improve mac reset handling
authorChristian Lamparter <chunkeey@googlemail.com>
Mon, 13 Sep 2010 20:49:05 +0000 (22:49 +0200)
committerChristian Lamparter <chunkeey@googlemail.com>
Mon, 13 Sep 2010 20:49:05 +0000 (22:49 +0200)
Extensive testing has confirmed that the code from the original
firmware source might not be sufficient to restore the MAC-state
after a reset.

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
carlfw/include/carl9170.h
carlfw/include/dma.h
carlfw/src/wlan.c

index 72b84b5f8da83a373b40b2e3ec4544d46e8c60c3..2b890fbe2343f1bdddc0bc8ceda4d396fdc3da1d 100644 (file)
@@ -100,6 +100,7 @@ struct firmware_context_struct {
                unsigned int rx_total;
                unsigned int rx_overruns;
                unsigned int mac_reset;
+               unsigned int soft_int;
 
 #ifdef CONFIG_CARL9170FW_CAB_QUEUE
                /* CAB */
index 9ccdd945c61457bcc6bbb3241ec8ea6d10128cae..e8d813bb1c77913d5e258e76dec8c7e1aa9615bc 100644 (file)
@@ -226,6 +226,11 @@ void dma_queue_reclaim(struct dma_queue *dst, struct dma_queue *src);
 void queue_dump(void);
 void wlan_txq_hangfix(const unsigned int queue);
 
+static inline __inline bool is_terminator(struct dma_queue *q, struct dma_desc *desc)
+{
+       return q->terminator == desc;
+}
+
 static inline __inline bool queue_empty(struct dma_queue *q)
 {
        return q->head == q->terminator;
index 947652486205e9092689327a08b5000e3bc56c63..09f48fdc43b4640fbcfaf595eab10730c07a95ce 100644 (file)
@@ -784,6 +784,9 @@ void handle_wlan(void)
                }                                       \
        } while (0)
 
+       intr |= fw.wlan.soft_int;
+       fw.wlan.soft_int = 0;
+
        HANDLER(intr, AR9170_MAC_INT_PRETBTT, handle_pretbtt);
 
        HANDLER(intr, AR9170_MAC_INT_ATIM, handle_atim);
@@ -911,6 +914,7 @@ static void wlan_mac_reset(void)
        uint32_t cam_mode;
        uint32_t ack_power;
        uint32_t rts_cts_tpc;
+       uint32_t rts_cts_rate;
        unsigned int i;
 
 #ifdef CONFIG_CARL9170FW_RADIO_FUNCTIONS
@@ -931,6 +935,7 @@ static void wlan_mac_reset(void)
 
        ack_power = get(AR9170_MAC_REG_ACK_TPC);
        rts_cts_tpc = get(AR9170_MAC_REG_RTS_CTS_TPC);
+       rts_cts_rate = get(AR9170_MAC_REG_RTS_CTS_RATE);
 
 #ifdef CONFIG_CARL9170FW_RADIO_FUNCTIONS
        /* 0x1c8960 write only */
@@ -972,6 +977,7 @@ static void wlan_mac_reset(void)
 
        set(AR9170_MAC_REG_RTS_CTS_TPC, rts_cts_tpc);
        set(AR9170_MAC_REG_ACK_TPC, ack_power);
+       set(AR9170_MAC_REG_RTS_CTS_RATE, rts_cts_rate);
 
 #ifdef CONFIG_CARL9170FW_RADIO_FUNCTIONS
        set(AR9170_PHY_REG_SWITCH_CHAIN_2, rx_BB);
@@ -983,17 +989,24 @@ static void wlan_mac_reset(void)
         * set(AR9170_PHY_REG_CCA_THRESHOLD, 0x0);
         */
 
+       /* Reinitialize all WLAN TX DMA queues. */
        for (i = 0; i < __AR9170_NUM_TX_QUEUES; i++) {
-               DBG("Q:%d l:%d h:%p t:%p\n", i, queue_len(&fw.wlan.tx_queue[i]),
-                    fw.wlan.tx_queue[i].head, fw.wlan.tx_queue[i].terminator);
+               struct dma_desc *iter;
 
-               set_wlan_txq_dma_addr(i, (uint32_t) fw.wlan.tx_queue[i].head);
+               __for_each_desc_bits(iter, &fw.wlan.tx_queue[i], AR9170_OWN_BITS_SW);
 
-               if (!queue_empty(&fw.wlan.tx_queue[i]))
+               set_wlan_txq_dma_addr(i, (uint32_t) iter);
+               if (!is_terminator(&fw.wlan.tx_queue[i], iter))
                        wlan_trigger(BIT(i));
+
+               DBG("Q:%d l:%d h:%p t:%p cu:%p it:%p ct:%x st:%x\n", i, queue_len(&fw.wlan.tx_queue[i]),
+                    fw.wlan.tx_queue[i].head, fw.wlan.tx_queue[i].terminator,
+                    get_wlan_txq_addr(i), iter, iter->ctrl, iter->status);
        }
 
-       handle_rx();
+       fw.wlan.soft_int |= AR9170_MAC_INT_RXC | AR9170_MAC_INT_TXC |
+                           AR9170_MAC_INT_RETRY_FAIL;
+
        set(AR9170_MAC_REG_DMA_RXQ_ADDR, (uint32_t) fw.wlan.rx_queue.head);
        wlan_trigger(AR9170_DMA_TRIGGER_RXQ);
 }