aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/ar9003_hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/ar9003_hw.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index f1d3c4aa2396..75a6d85d6ee9 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -892,6 +892,77 @@ static void ar9003_hw_init_hang_checks(struct ath_hw *ah)
892 ah->bb_watchdog_timeout_ms = 25; 892 ah->bb_watchdog_timeout_ms = 25;
893} 893}
894 894
895static bool ath9k_hw_check_dcs(u32 dma_dbg, u32 num_dcu_states,
896 int *hang_state, int *hang_pos)
897{
898 static u32 dcu_chain_state[] = {5, 6, 9}; /* DCU chain stuck states */
899 u32 chain_state, dcs_pos, i;
900
901 for (dcs_pos = 0; dcs_pos < num_dcu_states; dcs_pos++) {
902 chain_state = (dma_dbg >> (5 * dcs_pos)) & 0x1f;
903 for (i = 0; i < 3; i++) {
904 if (chain_state == dcu_chain_state[i]) {
905 *hang_state = chain_state;
906 *hang_pos = dcs_pos;
907 return true;
908 }
909 }
910 }
911 return false;
912}
913
914#define DCU_COMPLETE_STATE 1
915#define DCU_COMPLETE_STATE_MASK 0x3
916#define NUM_STATUS_READS 50
917
918static bool ar9003_hw_detect_mac_hang(struct ath_hw *ah)
919{
920 u32 chain_state, comp_state, dcs_reg = AR_DMADBG_4;
921 u32 i, hang_pos, hang_state, num_state = 6;
922
923 comp_state = REG_READ(ah, AR_DMADBG_6);
924
925 if ((comp_state & DCU_COMPLETE_STATE_MASK) != DCU_COMPLETE_STATE) {
926 ath_dbg(ath9k_hw_common(ah), RESET,
927 "MAC Hang signature not found at DCU complete\n");
928 return false;
929 }
930
931 chain_state = REG_READ(ah, dcs_reg);
932 if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos))
933 goto hang_check_iter;
934
935 dcs_reg = AR_DMADBG_5;
936 num_state = 4;
937 chain_state = REG_READ(ah, dcs_reg);
938 if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos))
939 goto hang_check_iter;
940
941 ath_dbg(ath9k_hw_common(ah), RESET,
942 "MAC Hang signature 1 not found\n");
943 return false;
944
945hang_check_iter:
946 ath_dbg(ath9k_hw_common(ah), RESET,
947 "DCU registers: chain %08x complete %08x Hang: state %d pos %d\n",
948 chain_state, comp_state, hang_state, hang_pos);
949
950 for (i = 0; i < NUM_STATUS_READS; i++) {
951 chain_state = REG_READ(ah, dcs_reg);
952 chain_state = (chain_state >> (5 * hang_pos)) & 0x1f;
953 comp_state = REG_READ(ah, AR_DMADBG_6);
954
955 if (((comp_state & DCU_COMPLETE_STATE_MASK) !=
956 DCU_COMPLETE_STATE) ||
957 (chain_state != hang_state))
958 return false;
959 }
960
961 ath_dbg(ath9k_hw_common(ah), RESET, "MAC Hang signature 1 found\n");
962
963 return true;
964}
965
895/* Sets up the AR9003 hardware familiy callbacks */ 966/* Sets up the AR9003 hardware familiy callbacks */
896void ar9003_hw_attach_ops(struct ath_hw *ah) 967void ar9003_hw_attach_ops(struct ath_hw *ah)
897{ 968{
@@ -901,6 +972,7 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)
901 ar9003_hw_init_mode_regs(ah); 972 ar9003_hw_init_mode_regs(ah);
902 priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs; 973 priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
903 priv_ops->init_hang_checks = ar9003_hw_init_hang_checks; 974 priv_ops->init_hang_checks = ar9003_hw_init_hang_checks;
975 priv_ops->detect_mac_hang = ar9003_hw_detect_mac_hang;
904 976
905 ops->config_pci_powersave = ar9003_hw_configpcipowersave; 977 ops->config_pci_powersave = ar9003_hw_configpcipowersave;
906 978