ath5k: Minor QCU updates
authorNick Kossifidis <mick@madwifi.org>
Tue, 6 Jan 2009 15:27:06 +0000 (17:27 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 29 Jan 2009 20:59:53 +0000 (15:59 -0500)
* Sync qcu.c with legacy-hal
* Add some more comments
* Set QCU mask to save power (QCU mask controls which QCUs are attached
  to each DCU, we do a 1:1 mapping)

TODO: Use max QCU from EEPROM, further sync with legacy-hal and sam's
hal and a few more minor fixes.

I think after this we are ready to implement WME on the driver
part. Anyone interested ?

Signed-Off-by: Nick Kossifidis <mickflemm@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath5k/qcu.c

index 1b7bc50ea8eb212b68fdd51f96283de34998e693..5094c394a4b2c9b1270e7a8c664540b02e0a2bf0 100644 (file)
@@ -148,6 +148,7 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
  */
 u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
 {
+       u32 pending;
        ATH5K_TRACE(ah->ah_sc);
        AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
 
@@ -159,7 +160,15 @@ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
        if (ah->ah_version == AR5K_AR5210)
                return false;
 
-       return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT;
+       pending = (AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT);
+
+       /* It's possible to have no frames pending even if TXE
+        * is set. To indicate that q has not stopped return
+        * true */
+       if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
+               return true;
+
+       return pending;
 }
 
 /*
@@ -324,8 +333,18 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
                /*
                 * Set misc registers
                 */
-               ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY,
-                       AR5K_QUEUE_MISC(queue));
+               /* Enable DCU early termination for this queue */
+               AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+                                       AR5K_QCU_MISC_DCU_EARLY);
+
+               /* Enable DCU to wait for next fragment from QCU */
+               AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+                                       AR5K_DCU_MISC_FRAG_WAIT);
+
+               /* On Maui and Spirit use the global seqnum on DCU */
+               if (ah->ah_mac_version < AR5K_SREV_AR5211)
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+                                               AR5K_DCU_MISC_SEQNUM_CTL);
 
                if (tq->tqi_cbr_period) {
                        ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
@@ -341,7 +360,8 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
                                        AR5K_QCU_MISC_CBR_THRES_ENABLE);
                }
 
-               if (tq->tqi_ready_time)
+               if (tq->tqi_ready_time &&
+               (tq->tqi_type != AR5K_TX_QUEUE_ID_CAB))
                        ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
                                AR5K_QCU_RDYTIMECFG_INTVAL) |
                                AR5K_QCU_RDYTIMECFG_ENABLE,
@@ -383,13 +403,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
                                AR5K_DCU_MISC_ARBLOCK_CTL_S) |
                                AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
                                AR5K_DCU_MISC_BCN_ENABLE);
-
-                       ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
-                               (AR5K_TUNE_SW_BEACON_RESP -
-                               AR5K_TUNE_DMA_BEACON_RESP) -
-                               AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
-                               AR5K_QCU_RDYTIMECFG_ENABLE,
-                               AR5K_QUEUE_RDYTIMECFG(queue));
                        break;
 
                case AR5K_TX_QUEUE_CAB:
@@ -398,6 +411,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
                                AR5K_QCU_MISC_CBREXP_DIS |
                                AR5K_QCU_MISC_CBREXP_BCN_DIS);
 
+                       ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
+                               (AR5K_TUNE_SW_BEACON_RESP -
+                               AR5K_TUNE_DMA_BEACON_RESP) -
+                               AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
+                               AR5K_QCU_RDYTIMECFG_ENABLE,
+                               AR5K_QUEUE_RDYTIMECFG(queue));
+
                        AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
                                (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
                                AR5K_DCU_MISC_ARBLOCK_CTL_S));
@@ -413,6 +433,8 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
                        break;
                }
 
+               /* TODO: Handle frame compression */
+
                /*
                 * Enable interrupts for this tx queue
                 * in the secondary interrupt mask registers
@@ -483,6 +505,9 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
                 * by setting AR5K_TXNOFRM to zero */
                if (ah->ah_txq_imr_nofrm == 0)
                        ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
+
+               /* Set QCU mask for this DCU to save power */
+               AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
        }
 
        return 0;