summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabor Juhos <juhosg@openwrt.org>2011-06-21 11:23:51 +0200
committerJohn W. Linville <linville@tuxdriver.com>2011-06-22 16:09:57 -0400
commit7d95847c9b3631d31f657d8cede153b518ed9e2e (patch)
tree033508bc12802ca4e5121d61f3893e112e625e2c
parent4187afa29a73fec1f68243c03437e7c1b37f315d (diff)
downloadlwn-7d95847c9b3631d31f657d8cede153b518ed9e2e.tar.gz
lwn-7d95847c9b3631d31f657d8cede153b518ed9e2e.zip
ath9k: add external_reset callback to ath9k_platfom_data for AR9330
The patch adds a callback to ath9k_platform_data. If the callback is provided by the platform code, then it can be used to hard reset the WMAC device. The callback is required for doing a hard reset of the AR9330 chips to get them working again after a hang. Signed-off-by: Gabor Juhos <juhosg@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c35
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c1
-rw-r--r--include/linux/ath9k_platform.h1
4 files changed, 38 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 4da5284c7773..839ba64c9e49 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1161,6 +1161,41 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
rst_flags |= AR_RTC_RC_MAC_COLD;
}
+ if (AR_SREV_9330(ah)) {
+ int npend = 0;
+ int i;
+
+ /* AR9330 WAR:
+ * call external reset function to reset WMAC if:
+ * - doing a cold reset
+ * - we have pending frames in the TX queues
+ */
+
+ 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), ATH_DBG_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;
+ }
+
+ REG_WRITE(ah, AR_RTC_RESET, 1);
+ }
+ }
+
REG_WRITE(ah, AR_RTC_RC, rst_flags);
REGWRITE_BUFFER_FLUSH(ah);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 0749fa8c3a58..818acdd1ba90 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -863,6 +863,7 @@ struct ath_hw {
bool is_clk_25mhz;
int (*get_mac_revision)(void);
+ int (*external_reset)(void);
};
struct ath_bus_ops {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 1851c222fff0..50103b2792b5 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -575,6 +575,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
sc->sc_ah->led_pin = pdata->led_pin;
ah->is_clk_25mhz = pdata->is_clk_25mhz;
ah->get_mac_revision = pdata->get_mac_revision;
+ ah->external_reset = pdata->external_reset;
}
common = ath9k_hw_common(ah);
diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h
index c207607acada..6e3f54f37844 100644
--- a/include/linux/ath9k_platform.h
+++ b/include/linux/ath9k_platform.h
@@ -31,6 +31,7 @@ struct ath9k_platform_data {
bool is_clk_25mhz;
int (*get_mac_revision)(void);
+ int (*external_reset)(void);
};
#endif /* _LINUX_ATH9K_PLATFORM_H */