summaryrefslogtreecommitdiffstats
path: root/sys/contrib/dev
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2014-08-09 09:12:25 +0000
committeradrian <adrian@FreeBSD.org>2014-08-09 09:12:25 +0000
commite357abc3e23281b44852edeb60c6d4b3896584e7 (patch)
treef9fe92fc66931b2d0ae1a7d4c578f92158c0e111 /sys/contrib/dev
parent41802e2c869ef8b626b1815870a3f7ede579e53f (diff)
downloadFreeBSD-src-e357abc3e23281b44852edeb60c6d4b3896584e7.zip
FreeBSD-src-e357abc3e23281b44852edeb60c6d4b3896584e7.tar.gz
Work around some rather annoying chip hangs in the AR9331 chip.
If powersave is enabled and there are any transitions to network or full sleep - even if they're pretty damned brief - eventually something messes up somewhere and the bus glue between the AR9331 SoC and the AR9331 wifi stops working. It shows up as stuck DMA and LOCAL_TIMEOUT interrupts. Both ath9k and the reference driver does a full chip reset if things get stuck. So: * teach the AR9330 HAL about the force_full_reset option I added a couple of years ago; * if the chip is currently in full-sleep, do a full-reset; * if TX DMA and/or RX DMA are still enabled (eg, they did get stuck during reset) then do a full-reset. Tested: * AR9331 SoC, STA mode
Diffstat (limited to 'sys/contrib/dev')
-rw-r--r--sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c
index a52f01e..1090c9c 100644
--- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c
+++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c
@@ -1987,13 +1987,25 @@ HAL_BOOL
ar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *chan)
{
struct ath_hal_9300 *ahp = AH9300(ah);
+ int type = HAL_RESET_WARM;
OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);
/*
* Warm reset is optimistic.
+ *
+ * If the TX/RX DMA engines aren't shut down (eg, they're
+ * wedged) then we're better off doing a full cold reset
+ * to try and shake that condition.
*/
- if (!ar9300_set_reset_reg(ah, HAL_RESET_WARM)) {
+ if (ahp->ah_chip_full_sleep ||
+ (ah->ah_config.ah_force_full_reset == 1) ||
+ OS_REG_READ(ah, AR_Q_TXE) ||
+ (OS_REG_READ(ah, AR_CR) & AR_CR_RXE)) {
+ type = HAL_RESET_COLD;
+ }
+
+ if (!ar9300_set_reset_reg(ah, type)) {
return AH_FALSE;
}
OpenPOWER on IntegriCloud