openwrtv4/package/kernel/mac80211/patches/315-ath9k_hw-issue-external-reset-for-QCA955x.patch
Felix Fietkau c9c68c7177 ath9k: fix issues with external reset on AR913x
An external reset patch for AR955x accidentally led to external reset
being issued twice on AR913x, once before the RTC reset and once after.
This may be causing some stability issues.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
2016-12-27 20:55:35 +01:00

126 lines
3.1 KiB
Diff

From: Felix Fietkau <nbd@nbd.name>
Date: Sat, 9 Jul 2016 15:26:44 +0200
Subject: [PATCH] ath9k_hw: issue external reset for QCA955x
The RTC interface on the SoC needs to be reset along with the rest of
the WMAC.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1271,39 +1271,56 @@ void ath9k_hw_get_delta_slope_vals(struc
*coef_exponent = coef_exp - 16;
}
-/* AR9330 WAR:
- * call external reset function to reset WMAC if:
- * - doing a cold reset
- * - we have pending frames in the TX queues.
- */
-static bool ath9k_hw_ar9330_reset_war(struct ath_hw *ah, int type)
+static bool ath9k_hw_need_external_reset(struct ath_hw *ah, int type)
{
- int i, npend = 0;
+ int i;
- for (i = 0; i < AR_NUM_QCU; i++) {
- npend = ath9k_hw_numtxpending(ah, i);
- if (npend)
- break;
+ if (type == ATH9K_RESET_COLD)
+ return true;
+
+ if (AR_SREV_9550(ah))
+ return true;
+
+ /* AR9330 WAR:
+ * call external reset function to reset WMAC if:
+ * - doing a cold reset
+ * - we have pending frames in the TX queues.
+ */
+ if (AR_SREV_9330(ah)) {
+ for (i = 0; i < AR_NUM_QCU; i++) {
+ if (ath9k_hw_numtxpending(ah, i))
+ return true;
+ }
}
- if (ah->external_reset &&
- (npend || type == ATH9K_RESET_COLD)) {
- int reset_err = 0;
+ return false;
+}
- ath_dbg(ath9k_hw_common(ah), RESET,
- "reset MAC via external reset\n");
+static bool ath9k_hw_external_reset(struct ath_hw *ah, int type)
+{
+ int err;
- reset_err = ah->external_reset();
- if (reset_err) {
- ath_err(ath9k_hw_common(ah),
- "External reset failed, err=%d\n",
- reset_err);
- return false;
- }
+ if (!ah->external_reset || !ath9k_hw_need_external_reset(ah, type))
+ return true;
- REG_WRITE(ah, AR_RTC_RESET, 1);
+ ath_dbg(ath9k_hw_common(ah), RESET,
+ "reset MAC via external reset\n");
+
+ err = ah->external_reset();
+ if (err) {
+ ath_err(ath9k_hw_common(ah),
+ "External reset failed, err=%d\n", err);
+ return false;
+ }
+
+ if (AR_SREV_9550(ah)) {
+ REG_WRITE(ah, AR_RTC_RESET, 0);
+ udelay(10);
}
+ REG_WRITE(ah, AR_RTC_RESET, 1);
+ udelay(10);
+
return true;
}
@@ -1356,24 +1373,24 @@ static bool ath9k_hw_set_reset(struct at
rst_flags |= AR_RTC_RC_MAC_COLD;
}
- if (AR_SREV_9330(ah)) {
- if (!ath9k_hw_ar9330_reset_war(ah, type))
- return false;
- }
-
if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_check_gpm_offset(ah);
/* DMA HALT added to resolve ar9300 and ar9580 bus error during
- * RTC_RC reg read
+ * RTC_RC reg read. Also needed for AR9550 external reset
*/
- if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) {
+ if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) {
REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK,
20 * AH_WAIT_TIMEOUT);
- REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
}
+ if (!AR_SREV_9100(ah))
+ ath9k_hw_external_reset(ah, type);
+
+ if (AR_SREV_9300(ah) || AR_SREV_9580(ah))
+ REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
+
REG_WRITE(ah, AR_RTC_RC, rst_flags);
REGWRITE_BUFFER_FLUSH(ah);