|
|
@@ -0,0 +1,125 @@
|
|
|
+From: Felix Fietkau <[email protected]>
|
|
|
+Date: Sat, 9 Jul 2016 15:26:44 +0200
|
|
|
+Subject: [PATCH] ath9k_hw: issue external reset for QCA9550
|
|
|
+
|
|
|
+The RTC interface on the SoC needs to be reset along with the rest of
|
|
|
+the WMAC.
|
|
|
+
|
|
|
+Signed-off-by: Felix Fietkau <[email protected]>
|
|
|
+---
|
|
|
+
|
|
|
+--- a/drivers/net/wireless/ath/ath9k/hw.c
|
|
|
++++ b/drivers/net/wireless/ath/ath9k/hw.c
|
|
|
+@@ -1275,39 +1275,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;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -1360,24 +1377,23 @@ 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);
|
|
|
+ }
|
|
|
+
|
|
|
++ 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);
|