diff options
author | Troy Tan <troy_tan@realsil.com.cn> | 2015-01-20 12:01:26 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-02-03 08:10:41 -0500 |
commit | 21b39ddb5bb2294fe64fbd29045591fe0707825f (patch) | |
tree | b9859003ecb40f4c13ca6ec3fe210ae4eb4545d6 /drivers/net/wireless | |
parent | 92ff754240b892cbc16dee5aa080322f3db88b68 (diff) |
rtlwifi: rtl8192ee: Fix DMA stalls
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>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/rtlwifi/rtl8192ee/hw.c | 140 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/rtl8192ee/reg.h | 2 |
2 files changed, 142 insertions, 0 deletions
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c index 3c27ec2c7b5a..b461b3128da5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c | |||
@@ -1137,6 +1137,139 @@ void rtl92ee_enable_hw_security_config(struct ieee80211_hw *hw) | |||
1137 | rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); | 1137 | rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); |
1138 | } | 1138 | } |
1139 | 1139 | ||
1140 | static bool _rtl8192ee_check_pcie_dma_hang(struct rtl_priv *rtlpriv) | ||
1141 | { | ||
1142 | u8 tmp; | ||
1143 | |||
1144 | /* write reg 0x350 Bit[26]=1. Enable debug port. */ | ||
1145 | tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3); | ||
1146 | if (!(tmp & BIT(2))) { | ||
1147 | rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3, | ||
1148 | tmp | BIT(2)); | ||
1149 | mdelay(100); /* Suggested by DD Justin_tsai. */ | ||
1150 | } | ||
1151 | |||
1152 | /* read reg 0x350 Bit[25] if 1 : RX hang | ||
1153 | * read reg 0x350 Bit[24] if 1 : TX hang | ||
1154 | */ | ||
1155 | tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3); | ||
1156 | if ((tmp & BIT(0)) || (tmp & BIT(1))) { | ||
1157 | RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, | ||
1158 | "CheckPcieDMAHang8192EE(): true!!\n"); | ||
1159 | return true; | ||
1160 | } | ||
1161 | return false; | ||
1162 | } | ||
1163 | |||
1164 | static void _rtl8192ee_reset_pcie_interface_dma(struct rtl_priv *rtlpriv, | ||
1165 | bool mac_power_on) | ||
1166 | { | ||
1167 | u8 tmp; | ||
1168 | bool release_mac_rx_pause; | ||
1169 | u8 backup_pcie_dma_pause; | ||
1170 | |||
1171 | RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, | ||
1172 | "ResetPcieInterfaceDMA8192EE()\n"); | ||
1173 | |||
1174 | /* Revise Note: Follow the document "PCIe RX DMA Hang Reset Flow_v03" | ||
1175 | * released by SD1 Alan. | ||
1176 | */ | ||
1177 | |||
1178 | /* 1. disable register write lock | ||
1179 | * write 0x1C bit[1:0] = 2'h0 | ||
1180 | * write 0xCC bit[2] = 1'b1 | ||
1181 | */ | ||
1182 | tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL); | ||
1183 | tmp &= ~(BIT(1) | BIT(0)); | ||
1184 | rtl_write_byte(rtlpriv, REG_RSV_CTRL, tmp); | ||
1185 | tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2); | ||
1186 | tmp |= BIT(2); | ||
1187 | rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp); | ||
1188 | |||
1189 | /* 2. Check and pause TRX DMA | ||
1190 | * write 0x284 bit[18] = 1'b1 | ||
1191 | * write 0x301 = 0xFF | ||
1192 | */ | ||
1193 | tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL); | ||
1194 | if (tmp & BIT(2)) { | ||
1195 | /* Already pause before the function for another reason. */ | ||
1196 | release_mac_rx_pause = false; | ||
1197 | } else { | ||
1198 | rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, (tmp | BIT(2))); | ||
1199 | release_mac_rx_pause = true; | ||
1200 | } | ||
1201 | |||
1202 | backup_pcie_dma_pause = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 1); | ||
1203 | if (backup_pcie_dma_pause != 0xFF) | ||
1204 | rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFF); | ||
1205 | |||
1206 | if (mac_power_on) { | ||
1207 | /* 3. reset TRX function | ||
1208 | * write 0x100 = 0x00 | ||
1209 | */ | ||
1210 | rtl_write_byte(rtlpriv, REG_CR, 0); | ||
1211 | } | ||
1212 | |||
1213 | /* 4. Reset PCIe DMA | ||
1214 | * write 0x003 bit[0] = 0 | ||
1215 | */ | ||
1216 | tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); | ||
1217 | tmp &= ~(BIT(0)); | ||
1218 | rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp); | ||
1219 | |||
1220 | /* 5. Enable PCIe DMA | ||
1221 | * write 0x003 bit[0] = 1 | ||
1222 | */ | ||
1223 | tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); | ||
1224 | tmp |= BIT(0); | ||
1225 | rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp); | ||
1226 | |||
1227 | if (mac_power_on) { | ||
1228 | /* 6. enable TRX function | ||
1229 | * write 0x100 = 0xFF | ||
1230 | */ | ||
1231 | rtl_write_byte(rtlpriv, REG_CR, 0xFF); | ||
1232 | |||
1233 | /* We should init LLT & RQPN and | ||
1234 | * prepare Tx/Rx descrptor address later | ||
1235 | * because MAC function is reset. | ||
1236 | */ | ||
1237 | } | ||
1238 | |||
1239 | /* 7. Restore PCIe autoload down bit | ||
1240 | * write 0xF8 bit[17] = 1'b1 | ||
1241 | */ | ||
1242 | tmp = rtl_read_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2); | ||
1243 | tmp |= BIT(1); | ||
1244 | rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2, tmp); | ||
1245 | |||
1246 | /* In MAC power on state, BB and RF maybe in ON state, | ||
1247 | * if we release TRx DMA here | ||
1248 | * it will cause packets to be started to Tx/Rx, | ||
1249 | * so we release Tx/Rx DMA later. | ||
1250 | */ | ||
1251 | if (!mac_power_on) { | ||
1252 | /* 8. release TRX DMA | ||
1253 | * write 0x284 bit[18] = 1'b0 | ||
1254 | * write 0x301 = 0x00 | ||
1255 | */ | ||
1256 | if (release_mac_rx_pause) { | ||
1257 | tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL); | ||
1258 | rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, | ||
1259 | (tmp & (~BIT(2)))); | ||
1260 | } | ||
1261 | rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, | ||
1262 | backup_pcie_dma_pause); | ||
1263 | } | ||
1264 | |||
1265 | /* 9. lock system register | ||
1266 | * write 0xCC bit[2] = 1'b0 | ||
1267 | */ | ||
1268 | tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2); | ||
1269 | tmp &= ~(BIT(2)); | ||
1270 | rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp); | ||
1271 | } | ||
1272 | |||
1140 | int rtl92ee_hw_init(struct ieee80211_hw *hw) | 1273 | int rtl92ee_hw_init(struct ieee80211_hw *hw) |
1141 | { | 1274 | { |
1142 | struct rtl_priv *rtlpriv = rtl_priv(hw); | 1275 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
@@ -1162,6 +1295,13 @@ int rtl92ee_hw_init(struct ieee80211_hw *hw) | |||
1162 | rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_92E; | 1295 | rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_92E; |
1163 | } | 1296 | } |
1164 | 1297 | ||
1298 | if (_rtl8192ee_check_pcie_dma_hang(rtlpriv)) { | ||
1299 | RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "92ee dma hang!\n"); | ||
1300 | _rtl8192ee_reset_pcie_interface_dma(rtlpriv, | ||
1301 | rtlhal->mac_func_enable); | ||
1302 | rtlhal->mac_func_enable = false; | ||
1303 | } | ||
1304 | |||
1165 | rtstatus = _rtl92ee_init_mac(hw); | 1305 | rtstatus = _rtl92ee_init_mac(hw); |
1166 | 1306 | ||
1167 | rtl_write_byte(rtlpriv, 0x577, 0x03); | 1307 | rtl_write_byte(rtlpriv, 0x577, 0x03); |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h index 3f2a9596e7cd..1eaa1fab550d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h | |||
@@ -77,9 +77,11 @@ | |||
77 | #define REG_HIMRE 0x00B8 | 77 | #define REG_HIMRE 0x00B8 |
78 | #define REG_HISRE 0x00BC | 78 | #define REG_HISRE 0x00BC |
79 | 79 | ||
80 | #define REG_PMC_DBG_CTRL2 0x00CC | ||
80 | #define REG_EFUSE_ACCESS 0x00CF | 81 | #define REG_EFUSE_ACCESS 0x00CF |
81 | #define REG_HPON_FSM 0x00EC | 82 | #define REG_HPON_FSM 0x00EC |
82 | #define REG_SYS_CFG1 0x00F0 | 83 | #define REG_SYS_CFG1 0x00F0 |
84 | #define REG_MAC_PHY_CTRL_NORMAL 0x00F8 | ||
83 | #define REG_SYS_CFG2 0x00FC | 85 | #define REG_SYS_CFG2 0x00FC |
84 | 86 | ||
85 | #define REG_CR 0x0100 | 87 | #define REG_CR 0x0100 |