diff options
author | Adrian Chadd <adrian@FreeBSD.org> | 2014-08-09 09:12:25 +0000 |
---|---|---|
committer | Adrian Chadd <adrian@FreeBSD.org> | 2014-08-09 09:12:25 +0000 |
commit | 2dc7b713dedd54ac0898d06399b11f45a1530184 (patch) | |
tree | f9fe92fc66931b2d0ae1a7d4c578f92158c0e111 /sys/contrib | |
parent | afb69e6b3e0157d103a30c2d5b8a5c60684c659f (diff) | |
download | src-2dc7b713dedd54ac0898d06399b11f45a1530184.tar.gz src-2dc7b713dedd54ac0898d06399b11f45a1530184.zip |
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
Notes
Notes:
svn path=/head/; revision=269748
Diffstat (limited to 'sys/contrib')
-rw-r--r-- | sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c | 14 |
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 a52f01e227bb..1090c9c59ab7 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; } |