From 949e5e3c00b0ba908b2ef089ddc9cdc0ff660842 Mon Sep 17 00:00:00 2001 From: adrian Date: Mon, 25 May 2020 22:31:45 +0000 Subject: [PATCH] [ath] [ath_hal] Propagate the HAL_RESET_TYPE through to the chip reset; set it during ath_reset() Although I added the reset type field to ath_hal_reset() years ago, I never finished adding it both throughout the HALs and in if_ath.c. This will eventually deprecate the ath_hal force_full_reset option because it can be requested at the driver layer. So: * Teach ar5416ChipReset() and ar9300_chip_reset() about the HAL type * Use it in ar5416Reset() and ar9300_reset() when doing a full chip reset * Extend ath_reset() to include the HAL_RESET_TYPE parameter added in the above functions * Use HAL_RESET_NORMAL in most calls to ath_reset() * .. but use HAL_RESET_BBPANIC for the BB panics, and HAL_RESET_FORCE_COLD during fatal, beacon miss and other hardware related hangs. This should be a glorified no-op outside of actual hardware issues. I've tested things with ath_hal force_full_reset set to 1 for years now, so I know that feature and a full reset works (albeit much slower than a warm reset!) and it does unwedge hardware. The eventual aim is to use this for all the places where the driver detects a potential hang as well as if long calibration - ie, noise floor calibration - fails to complete. That's one of the big hardware related things that causes station mode operation to hang without easy recovery. Differential Revision: https://reviews.freebsd.org/D24981 --- sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h | 4 ++-- .../dev/ath/ath_hal/ar9300/ar9300_freebsd.c | 1 + .../dev/ath/ath_hal/ar9300/ar9300_reset.c | 11 +++++++--- sys/dev/ath/ath_hal/ar5416/ar5416.h | 3 ++- sys/dev/ath/ath_hal/ar5416/ar5416_attach.c | 2 +- sys/dev/ath/ath_hal/ar5416/ar5416_reset.c | 14 +++++++++++-- sys/dev/ath/ath_hal/ar9001/ar9130_attach.c | 2 +- sys/dev/ath/ath_hal/ar9001/ar9160_attach.c | 2 +- sys/dev/ath/ath_hal/ar9002/ar9280_attach.c | 2 +- sys/dev/ath/ath_hal/ar9002/ar9285_attach.c | 2 +- sys/dev/ath/ath_hal/ar9002/ar9287_attach.c | 2 +- sys/dev/ath/if_ath.c | 21 ++++++++++++------- sys/dev/ath/if_ath_misc.h | 3 ++- sys/dev/ath/if_ath_sysctl.c | 8 ++++--- 14 files changed, 51 insertions(+), 26 deletions(-) diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h index 13b5827083a..49e887353e5 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h @@ -1390,7 +1390,7 @@ extern void ar9300_wowoffload_download_ns_info(struct ath_hal *ah, u_int32_t id extern HAL_BOOL ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask, HAL_HT_EXTPROTSPACING extprotspacing, - HAL_BOOL b_channel_change, HAL_STATUS *status, int is_scan); + HAL_BOOL b_channel_change, HAL_STATUS *status, HAL_RESET_TYPE reset_type, int is_scan); extern HAL_BOOL ar9300_lean_channel_change(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask); extern HAL_BOOL ar9300_set_reset_reg(struct ath_hal *ah, u_int32_t type); @@ -1400,7 +1400,7 @@ extern u_int16_t ar9300_is_single_ant_power_save_possible(struct ath_hal *ah); extern void ar9300_set_operating_mode(struct ath_hal *ah, int opmode); extern HAL_BOOL ar9300_phy_disable(struct ath_hal *ah); extern HAL_BOOL ar9300_disable(struct ath_hal *ah); -extern HAL_BOOL ar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *); +extern HAL_BOOL ar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *, HAL_RESET_TYPE type); extern HAL_BOOL ar9300_calibration(struct ath_hal *ah, struct ieee80211_channel *chan, u_int8_t rxchainmask, HAL_BOOL longcal, HAL_BOOL *isIQdone, int is_scan, u_int32_t *sched_cals); extern void ar9300_reset_cal_valid(struct ath_hal *ah, diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c index 9814d0508df..37e64bc86cd 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c @@ -543,6 +543,7 @@ ar9300_reset_freebsd(struct ath_hal *ah, HAL_OPMODE opmode, HAL_HT_EXTPROTSPACING_20, /* always 20Mhz channel spacing */ bChannelChange, status, + resetType, AH_FALSE); /* XXX should really extend ath_hal_reset() */ return (r); 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 40cdbdd173f..2b4374d237b 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c @@ -2064,7 +2064,7 @@ ar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan) * Places the hardware into reset and then pulls it out of reset */ HAL_BOOL -ar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *chan) +ar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_RESET_TYPE reset_type) { struct ath_hal_9300 *ahp = AH9300(ah); int type = HAL_RESET_WARM; @@ -2080,8 +2080,13 @@ ar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *chan) */ if (ahp->ah_chip_full_sleep || (ah->ah_config.ah_force_full_reset == 1) || + (reset_type == HAL_RESET_FORCE_COLD) || + (reset_type == HAL_RESET_BBPANIC) || OS_REG_READ(ah, AR_Q_TXE) || (OS_REG_READ(ah, AR_CR) & AR_CR_RXE)) { + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s: full reset; reset_type=%d, full_sleep=%d\n", + __func__, reset_type, ahp->ah_chip_full_sleep); type = HAL_RESET_COLD; } @@ -4510,7 +4515,7 @@ HAL_BOOL ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask, HAL_HT_EXTPROTSPACING extprotspacing, HAL_BOOL b_channel_change, - HAL_STATUS *status, int is_scan) + HAL_STATUS *status, HAL_RESET_TYPE reset_type, int is_scan) { #define FAIL(_code) do { ecode = _code; goto bad; } while (0) u_int32_t save_led_state; @@ -4864,7 +4869,7 @@ ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *ch /* Mark PHY inactive prior to reset, to be undone in ar9300_init_bb () */ ar9300_mark_phy_inactive(ah); - if (!ar9300_chip_reset(ah, chan)) { + if (!ar9300_chip_reset(ah, chan, reset_type)) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: chip reset failed\n", __func__); FAIL(HAL_EIO); } diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416.h b/sys/dev/ath/ath_hal/ar5416/ar5416.h index 7e167709fa7..3f0787ec17c 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416.h +++ b/sys/dev/ath/ath_hal/ar5416/ar5416.h @@ -306,7 +306,8 @@ extern HAL_BOOL ar5416PhyDisable(struct ath_hal *ah); extern HAL_RFGAIN ar5416GetRfgain(struct ath_hal *ah); extern HAL_BOOL ar5416Disable(struct ath_hal *ah); extern HAL_BOOL ar5416ChipReset(struct ath_hal *ah, - const struct ieee80211_channel *); + const struct ieee80211_channel *, + HAL_RESET_TYPE); extern int ar5416GetRegChainOffset(struct ath_hal *ah, int i); extern HAL_BOOL ar5416SetBoardValues(struct ath_hal *, const struct ieee80211_channel *); diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c index 8957dedb39d..6d8dfd3b856 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c @@ -376,7 +376,7 @@ ar5416Attach(uint16_t devid, HAL_SOFTC sc, if (ecode != HAL_OK) goto bad; - if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ + if (!ar5416ChipReset(ah, AH_NULL, HAL_RESET_NORMAL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c index 6c5cf53c325..7501885be6f 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c @@ -170,13 +170,15 @@ ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, if (AR_SREV_HOWL(ah) || (AR_SREV_MERLIN(ah) && ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) || + (resetType == HAL_RESET_FORCE_COLD) || + (resetType == HAL_RESET_BBPANIC) || (ah->ah_config.ah_force_full_reset)) tsf = ar5416GetTsf64(ah); /* Mark PHY as inactive; marked active in ar5416InitBB() */ ar5416MarkPhyInactive(ah); - if (!ar5416ChipReset(ah, chan)) { + if (!ar5416ChipReset(ah, chan, resetType)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); FAIL(HAL_EIO); } @@ -775,7 +777,8 @@ ar5416SetRfMode(struct ath_hal *ah, const struct ieee80211_channel *chan) * Places the hardware into reset and then pulls it out of reset */ HAL_BOOL -ar5416ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan) +ar5416ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan, + HAL_RESET_TYPE resetType) { OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0); /* @@ -788,6 +791,13 @@ ar5416ChipReset(struct ath_hal *ah, const struct ieee80211_channel *chan) } else if (ah->ah_config.ah_force_full_reset) { if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) return AH_FALSE; + } else if ((resetType == HAL_RESET_FORCE_COLD) || + (resetType == HAL_RESET_BBPANIC)) { + HALDEBUG(ah, HAL_DEBUG_RESET, + "%s: full reset; resetType=%d\n", + __func__, resetType); + if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) + return AH_FALSE; } else { if (!ar5416SetResetReg(ah, HAL_RESET_WARM)) return AH_FALSE; diff --git a/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c b/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c index 1d78b053c37..85389792219 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c +++ b/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c @@ -173,7 +173,7 @@ ar9130Attach(uint16_t devid, HAL_SOFTC sc, if (ecode != HAL_OK) goto bad; - if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ + if (!ar5416ChipReset(ah, AH_NULL, HAL_RESET_NORMAL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; diff --git a/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c b/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c index f74da22d1e7..b67699358aa 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c +++ b/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c @@ -200,7 +200,7 @@ ar9160Attach(uint16_t devid, HAL_SOFTC sc, HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9160PciePhy, 2); ar5416AttachPCIE(ah); - if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ + if (!ar5416ChipReset(ah, AH_NULL, HAL_RESET_NORMAL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c index 92479214e5a..d6336bef734 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c @@ -259,7 +259,7 @@ ar9280Attach(uint16_t devid, HAL_SOFTC sc, if (ecode != HAL_OK) goto bad; - if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ + if (!ar5416ChipReset(ah, AH_NULL, HAL_RESET_NORMAL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c index 5c140b98dbb..718a89995df 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c @@ -249,7 +249,7 @@ ar9285Attach(uint16_t devid, HAL_SOFTC sc, if (ecode != HAL_OK) goto bad; - if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ + if (!ar5416ChipReset(ah, AH_NULL, HAL_RESET_NORMAL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c index 8341535bdb9..b5173dab309 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c @@ -242,7 +242,7 @@ ar9287Attach(uint16_t devid, HAL_SOFTC sc, if (ecode != HAL_OK) goto bad; - if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ + if (!ar5416ChipReset(ah, AH_NULL, HAL_RESET_NORMAL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 7cadbfd3b11..660547f3270 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -2380,7 +2380,7 @@ ath_fatal_proc(void *arg, int pending) "0x%08x 0x%08x 0x%08x, 0x%08x 0x%08x 0x%08x\n", state[0], state[1] , state[2], state[3], state[4], state[5]); } - ath_reset(sc, ATH_RESET_NOLOSS); + ath_reset(sc, ATH_RESET_NOLOSS, HAL_RESET_FORCE_COLD); } static void @@ -2491,11 +2491,11 @@ ath_bmiss_proc(void *arg, int pending) * to clear. */ if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0) { - ath_reset(sc, ATH_RESET_NOLOSS); + ath_reset(sc, ATH_RESET_NOLOSS, HAL_RESET_BBPANIC); device_printf(sc->sc_dev, "bb hang detected (0x%x), resetting\n", hangs); } else { - ath_reset(sc, ATH_RESET_NOLOSS); + ath_reset(sc, ATH_RESET_NOLOSS, HAL_RESET_FORCE_COLD); ieee80211_beacon_miss(&sc->sc_ic); } @@ -2894,7 +2894,8 @@ ath_reset_grablock(struct ath_softc *sc, int dowait) * to reset or reload hardware state. */ int -ath_reset(struct ath_softc *sc, ATH_RESET_TYPE reset_type) +ath_reset(struct ath_softc *sc, ATH_RESET_TYPE reset_type, + HAL_RESET_TYPE ah_reset_type) { struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; @@ -2962,7 +2963,7 @@ ath_reset(struct ath_softc *sc, ATH_RESET_TYPE reset_type) ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask, sc->sc_cur_rxchainmask); if (!ath_hal_reset(ah, sc->sc_opmode, ic->ic_curchan, AH_TRUE, - HAL_RESET_NORMAL, &status)) + ah_reset_type, &status)) device_printf(sc->sc_dev, "%s: unable to reset hardware; hal status %u\n", __func__, status); @@ -3098,7 +3099,7 @@ ath_reset_vap(struct ieee80211vap *vap, u_long cmd) return 0; } /* XXX? Full or NOLOSS? */ - return ath_reset(sc, ATH_RESET_FULL); + return ath_reset(sc, ATH_RESET_FULL, HAL_RESET_NORMAL); } struct ath_buf * @@ -3778,7 +3779,7 @@ ath_reset_proc(void *arg, int pending) #if 0 device_printf(sc->sc_dev, "%s: resetting\n", __func__); #endif - ath_reset(sc, ATH_RESET_NOLOSS); + ath_reset(sc, ATH_RESET_NOLOSS, HAL_RESET_FORCE_COLD); } /* @@ -3805,7 +3806,7 @@ ath_bstuck_proc(void *arg, int pending) * This assumes that there's no simultaneous channel mode change * occurring. */ - ath_reset(sc, ATH_RESET_NOLOSS); + ath_reset(sc, ATH_RESET_NOLOSS, HAL_RESET_FORCE_COLD); } static int @@ -5460,6 +5461,10 @@ ath_calibrate(void *arg) * infinite NIC restart. Ideally we'd not restart if we * failed the first NF cal - that /can/ fail sometimes in * a noisy environment. + * + * Instead, we should likely temporarily shorten the longCal + * period to happen pretty quickly and if a subsequent one + * fails, do a full reset. */ if (shortCal) sc->sc_lastshortcal = ticks; diff --git a/sys/dev/ath/if_ath_misc.h b/sys/dev/ath/if_ath_misc.h index d3e6b3ad313..b108c29bab4 100644 --- a/sys/dev/ath/if_ath_misc.h +++ b/sys/dev/ath/if_ath_misc.h @@ -58,7 +58,8 @@ extern void ath_freebuf(struct ath_softc *sc, struct ath_buf *bf); extern void ath_returnbuf_head(struct ath_softc *sc, struct ath_buf *bf); extern void ath_returnbuf_tail(struct ath_softc *sc, struct ath_buf *bf); -extern int ath_reset(struct ath_softc *, ATH_RESET_TYPE); +extern int ath_reset(struct ath_softc *, ATH_RESET_TYPE, + HAL_RESET_TYPE ah_reset_type); extern void ath_tx_default_comp(struct ath_softc *sc, struct ath_buf *bf, int fail); extern void ath_tx_update_ratectrl(struct ath_softc *sc, diff --git a/sys/dev/ath/if_ath_sysctl.c b/sys/dev/ath/if_ath_sysctl.c index 662aa77008a..03a61b3a841 100644 --- a/sys/dev/ath/if_ath_sysctl.c +++ b/sys/dev/ath/if_ath_sysctl.c @@ -382,7 +382,8 @@ ath_sysctl_tpscale(SYSCTL_HANDLER_ARGS) goto finish; error = !ath_hal_settpscale(sc->sc_ah, scale) ? EINVAL : - (sc->sc_running) ? ath_reset(sc, ATH_RESET_NOLOSS) : 0; + (sc->sc_running) ? ath_reset(sc, ATH_RESET_NOLOSS, + HAL_RESET_NORMAL) : 0; finish: ATH_LOCK(sc); @@ -443,7 +444,8 @@ ath_sysctl_rfkill(SYSCTL_HANDLER_ARGS) error = EINVAL; goto finish; } - error = sc->sc_running ? ath_reset(sc, ATH_RESET_FULL) : 0; + error = sc->sc_running ? ath_reset(sc, ATH_RESET_FULL, + HAL_RESET_NORMAL) : 0; finish: ATH_LOCK(sc); @@ -670,7 +672,7 @@ ath_sysctl_intmit(SYSCTL_HANDLER_ARGS) * things in an inconsistent state. */ if (sc->sc_running) - ath_reset(sc, ATH_RESET_NOLOSS); + ath_reset(sc, ATH_RESET_NOLOSS, HAL_RESET_NORMAL); error = 0; -- 2.45.0