ath9k: Fix maximum tx fifo settings for single stream devices
authorLuis R. Rodriguez <lrodriguez@atheros.com>
Wed, 25 Nov 2009 02:37:57 +0000 (21:37 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Sat, 28 Nov 2009 20:04:52 +0000 (15:04 -0500)
Atheros single stream AR9285 and AR9271 have half the PCU TX FIFO
buffer size of that of dual stream devices. Dual stream devices
have a max PCU TX FIFO size of 8 KB while single stream devices
have 4 KB. Single stream devices have an issue though and require
hardware only to use half of the amount of its capable PCU TX FIFO
size, 2 KB and this requires a change in software.

Technically a change would not have been required (except for frame
burst considerations of 128 bytes) if these devices would have been
able to use the full 4 KB of the PCU TX FIFO size but our systems
engineers recommend 2 KB to be used only. We enforce this through
software by reducing the max frame triggger level to 2 KB.

Fixing the max frame trigger level should then have a few benefits:

  * The PER will now be adjusted as designed for underruns when the
    max trigger level is reached. This should help alleviate the
    bus as the rate control algorithm chooses a slower rate which
    should ensure frames are transmitted properly under high system
    bus load.

  * The poll we use on our TX queues should now trigger and work
    as designed for single stream devices. The hardware passes
    data from each TX queue on the PCU TX FIFO queue respecting each
    queue's priority. The new trigger level ensures this seeding of
    the PCU TX FIFO queue occurs as designed which could mean avoiding
    false resets and actually reseting hw correctly when a TX queue
    is indeed stuck.

  * Some undocumented / unsupported behaviour could have been triggered
    when the max trigger level level was being set to 4 KB on single
    stream devices. Its not clear what this issue was to me yet.

Cc: Kyungwan Nam <kyungwan.nam@atheros.com>
Cc: Bennyam Malavazi <bennyam.malavazi@atheros.com>
Cc: Stephen Chen <stephen.chen@atheros.com>
Cc: Shan Palanisamy <shan.palanisamy@atheros.com>
Cc: Paul Shaw <paul.shaw@atheros.com>
Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/rc.c

index 63d84613dc96e2382bc4a0021e1abb208e852d9c..493160c8c754428d833710f5631310cbcbecbc02 100644 (file)
@@ -918,6 +918,11 @@ int ath9k_hw_init(struct ath_hw *ah)
        ath_print(common, ATH_DBG_RESET, "serialize_regmode is %d\n",
                ah->config.serialize_regmode);
 
+       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+               ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1;
+       else
+               ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD;
+
        if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) {
                ath_print(common, ATH_DBG_FATAL,
                          "Mac Chip Rev 0x%02x.%x is not supported by "
@@ -3224,7 +3229,11 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
                pCap->keycache_size = AR_KEYTABLE_SIZE;
 
        pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
-       pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
+
+       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+               pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1;
+       else
+               pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
 
        if (AR_SREV_9285_10_OR_LATER(ah))
                pCap->num_gpio_pins = AR9285_NUM_GPIO;
index b12634262d97f452452d0181510af2ae18c52e6f..46e1572dc9459c3cfb146499de67b1b080c36e6d 100644 (file)
@@ -226,6 +226,7 @@ struct ath9k_ops_config {
 #define AR_SPUR_FEEQ_BOUND_HT20 10
        int spurmode;
        u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
+       u8 max_txtrig_level;
 };
 
 enum ath9k_int {
index 09ed441eb6ba82c3ce90581696b6cacd441abf61..71b84d91dcffbb2d6edd2e66ede4b9d73f1d9fab 100644 (file)
@@ -70,12 +70,37 @@ u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
 }
 EXPORT_SYMBOL(ath9k_hw_numtxpending);
 
+/**
+ * ath9k_hw_updatetxtriglevel - adjusts the frame trigger level
+ *
+ * @ah: atheros hardware struct
+ * @bIncTrigLevel: whether or not the frame trigger level should be updated
+ *
+ * The frame trigger level specifies the minimum number of bytes,
+ * in units of 64 bytes, that must be DMA'ed into the PCU TX FIFO
+ * before the PCU will initiate sending the frame on the air. This can
+ * mean we initiate transmit before a full frame is on the PCU TX FIFO.
+ * Resets to 0x1 (meaning 64 bytes or a full frame, whichever occurs
+ * first)
+ *
+ * Caution must be taken to ensure to set the frame trigger level based
+ * on the DMA request size. For example if the DMA request size is set to
+ * 128 bytes the trigger level cannot exceed 6 * 64 = 384. This is because
+ * there need to be enough space in the tx FIFO for the requested transfer
+ * size. Hence the tx FIFO will stop with 512 - 128 = 384 bytes. If we set
+ * the threshold to a value beyond 6, then the transmit will hang.
+ *
+ * Current dual   stream devices have a PCU TX FIFO size of 8 KB.
+ * Current single stream devices have a PCU TX FIFO size of 4 KB, however,
+ * there is a hardware issue which forces us to use 2 KB instead so the
+ * frame trigger level must not exceed 2 KB for these chipsets.
+ */
 bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
 {
        u32 txcfg, curLevel, newLevel;
        enum ath9k_int omask;
 
-       if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD)
+       if (ah->tx_trig_level >= ah->config.max_txtrig_level)
                return false;
 
        omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL);
@@ -84,7 +109,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
        curLevel = MS(txcfg, AR_FTRIG);
        newLevel = curLevel;
        if (bIncTrigLevel) {
-               if (curLevel < MAX_TX_FIFO_THRESHOLD)
+               if (curLevel < ah->config.max_txtrig_level)
                        newLevel++;
        } else if (curLevel > MIN_TX_FIFO_THRESHOLD)
                newLevel--;
index 6cc04951a051f5c1b64a462e5c078d8904e7d5c0..0c87771383f08902a0610b873ce04bc6f238b3f6 100644 (file)
 #define ATH9K_TX_SW_ABORTED        0x40
 #define ATH9K_TX_SW_FILTERED       0x80
 
+/* 64 bytes */
 #define MIN_TX_FIFO_THRESHOLD   0x1
+
+/*
+ * Single stream device AR9285 and AR9271 require 2 KB
+ * to work around a hardware issue, all other devices
+ * have can use the max 4 KB limit.
+ */
 #define MAX_TX_FIFO_THRESHOLD   ((4096 / 64) - 1)
-#define INIT_TX_FIFO_THRESHOLD  MIN_TX_FIFO_THRESHOLD
 
 struct ath_tx_status {
        u32 ts_tstamp;
index e697bd934904184edf9671e905a950ed8894b36f..c915954d4d5bff58d686a947492bba9b5ce96cec 100644 (file)
@@ -1235,10 +1235,14 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
                return;
 
        /*
-        * If underrun error is seen assume it as an excessive retry only
-        * if prefetch trigger level have reached the max (0x3f for 5416)
-        * Adjust the long retry as if the frame was tried hw->max_rate_tries
-        * times. This affects how ratectrl updates PER for the failed rate.
+        * If an underrun error is seen assume it as an excessive retry only
+        * if max frame trigger level has been reached (2 KB for singel stream,
+        * and 4 KB for dual stream). Adjust the long retry as if the frame was
+        * tried hw->max_rate_tries times to affect how ratectrl updates PER for
+        * the failed rate. In case of congestion on the bus penalizing these
+        * type of underruns should help hardware actually transmit new frames
+        * successfully by eventually preferring slower rates. This itself
+        * should also alleviate congestion on the bus.
         */
        if ((tx_info->pad[0] & ATH_TX_INFO_UNDERRUN) &&
            (sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) {