rtlwifi: rtl8192ee: Fix DMA stalls
authorTroy Tan <troy_tan@realsil.com.cn>
Tue, 20 Jan 2015 17:01:26 +0000 (11:01 -0600)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 3 Feb 2015 13:10:41 +0000 (15:10 +0200)
There are instances where the DMA engine stalls. The new code detects
such stalls and restarts DMA without needing a power reset.

Signed-off-by: Troy Tan <troy_tan@realsil.com.cn>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Stable <stable@vger.kernel.org> [3.18]
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
drivers/net/wireless/rtlwifi/rtl8192ee/reg.h

index 3c27ec2c7b5a821a1cc0c3242602ff2dcf8cc0f0..b461b3128da581bdb17ee53b1e5e9238472ca95b 100644 (file)
@@ -1137,6 +1137,139 @@ void rtl92ee_enable_hw_security_config(struct ieee80211_hw *hw)
        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
 }
 
+static bool _rtl8192ee_check_pcie_dma_hang(struct rtl_priv *rtlpriv)
+{
+       u8 tmp;
+
+       /* write reg 0x350 Bit[26]=1. Enable debug port. */
+       tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3);
+       if (!(tmp & BIT(2))) {
+               rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3,
+                              tmp | BIT(2));
+               mdelay(100); /* Suggested by DD Justin_tsai. */
+       }
+
+       /* read reg 0x350 Bit[25] if 1 : RX hang
+        * read reg 0x350 Bit[24] if 1 : TX hang
+        */
+       tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3);
+       if ((tmp & BIT(0)) || (tmp & BIT(1))) {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                        "CheckPcieDMAHang8192EE(): true!!\n");
+               return true;
+       }
+       return false;
+}
+
+static void _rtl8192ee_reset_pcie_interface_dma(struct rtl_priv *rtlpriv,
+                                               bool mac_power_on)
+{
+       u8 tmp;
+       bool release_mac_rx_pause;
+       u8 backup_pcie_dma_pause;
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "ResetPcieInterfaceDMA8192EE()\n");
+
+       /* Revise Note: Follow the document "PCIe RX DMA Hang Reset Flow_v03"
+        * released by SD1 Alan.
+        */
+
+       /* 1. disable register write lock
+        *      write 0x1C bit[1:0] = 2'h0
+        *      write 0xCC bit[2] = 1'b1
+        */
+       tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL);
+       tmp &= ~(BIT(1) | BIT(0));
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL, tmp);
+       tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2);
+       tmp |= BIT(2);
+       rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp);
+
+       /* 2. Check and pause TRX DMA
+        *      write 0x284 bit[18] = 1'b1
+        *      write 0x301 = 0xFF
+        */
+       tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+       if (tmp & BIT(2)) {
+               /* Already pause before the function for another reason. */
+               release_mac_rx_pause = false;
+       } else {
+               rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, (tmp | BIT(2)));
+               release_mac_rx_pause = true;
+       }
+
+       backup_pcie_dma_pause = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 1);
+       if (backup_pcie_dma_pause != 0xFF)
+               rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFF);
+
+       if (mac_power_on) {
+               /* 3. reset TRX function
+                *      write 0x100 = 0x00
+                */
+               rtl_write_byte(rtlpriv, REG_CR, 0);
+       }
+
+       /* 4. Reset PCIe DMA
+        *      write 0x003 bit[0] = 0
+        */
+       tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+       tmp &= ~(BIT(0));
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp);
+
+       /* 5. Enable PCIe DMA
+        *      write 0x003 bit[0] = 1
+        */
+       tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+       tmp |= BIT(0);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp);
+
+       if (mac_power_on) {
+               /* 6. enable TRX function
+                *      write 0x100 = 0xFF
+                */
+               rtl_write_byte(rtlpriv, REG_CR, 0xFF);
+
+               /* We should init LLT & RQPN and
+                * prepare Tx/Rx descrptor address later
+                * because MAC function is reset.
+                */
+       }
+
+       /* 7. Restore PCIe autoload down bit
+        *      write 0xF8 bit[17] = 1'b1
+        */
+       tmp = rtl_read_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2);
+       tmp |= BIT(1);
+       rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2, tmp);
+
+       /* In MAC power on state, BB and RF maybe in ON state,
+        * if we release TRx DMA here
+        * it will cause packets to be started to Tx/Rx,
+        * so we release Tx/Rx DMA later.
+        */
+       if (!mac_power_on) {
+               /* 8. release TRX DMA
+                *      write 0x284 bit[18] = 1'b0
+                *      write 0x301 = 0x00
+                */
+               if (release_mac_rx_pause) {
+                       tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+                       rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL,
+                                      (tmp & (~BIT(2))));
+               }
+               rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1,
+                              backup_pcie_dma_pause);
+       }
+
+       /* 9. lock system register
+        *      write 0xCC bit[2] = 1'b0
+        */
+       tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2);
+       tmp &= ~(BIT(2));
+       rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp);
+}
+
 int rtl92ee_hw_init(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1162,6 +1295,13 @@ int rtl92ee_hw_init(struct ieee80211_hw *hw)
                rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_92E;
        }
 
+       if (_rtl8192ee_check_pcie_dma_hang(rtlpriv)) {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "92ee dma hang!\n");
+               _rtl8192ee_reset_pcie_interface_dma(rtlpriv,
+                                                   rtlhal->mac_func_enable);
+               rtlhal->mac_func_enable = false;
+       }
+
        rtstatus = _rtl92ee_init_mac(hw);
 
        rtl_write_byte(rtlpriv, 0x577, 0x03);
index 3f2a9596e7cd89859928a797c52d7b6b13fad70d..1eaa1fab550dd1f88d7380d421018398677616e1 100644 (file)
 #define REG_HIMRE                              0x00B8
 #define REG_HISRE                              0x00BC
 
+#define REG_PMC_DBG_CTRL2                      0x00CC
 #define REG_EFUSE_ACCESS                       0x00CF
 #define REG_HPON_FSM                           0x00EC
 #define REG_SYS_CFG1                           0x00F0
+#define REG_MAC_PHY_CTRL_NORMAL                        0x00F8
 #define REG_SYS_CFG2                           0x00FC
 
 #define REG_CR                                 0x0100