mac80211: rebase ontop of v4.18-rc7
[openwrt/staging/blogic.git] / package / kernel / mac80211 / patches / ath / 351-ath9k_hw-issue-external-reset-for-QCA955x.patch
diff --git a/package/kernel/mac80211/patches/ath/351-ath9k_hw-issue-external-reset-for-QCA955x.patch b/package/kernel/mac80211/patches/ath/351-ath9k_hw-issue-external-reset-for-QCA955x.patch
new file mode 100644 (file)
index 0000000..5eb69b8
--- /dev/null
@@ -0,0 +1,129 @@
+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 (ah->external_reset &&
+-          (npend || type == ATH9K_RESET_COLD)) {
+-              int reset_err = 0;
+-
+-              ath_dbg(ath9k_hw_common(ah), RESET,
+-                      "reset MAC via external reset\n");
+-
+-              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 (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;
+               }
++      }
++
++      return false;
++}
++
++static bool ath9k_hw_external_reset(struct ath_hw *ah, int type)
++{
++      int err;
++
++      if (!ah->external_reset || !ath9k_hw_need_external_reset(ah, type))
++              return true;
++
++      ath_dbg(ath9k_hw_common(ah), RESET,
++              "reset MAC via external reset\n");
+-              REG_WRITE(ah, AR_RTC_RESET, 1);
++      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);