Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 42eda115 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville
Browse files

ath9k: Add recovery mechanism for hw TSF timer



Configure the TSF based hardware timer for a channel switch.
Also set up backup software timer, in case the gen timer fails.
This could be caused by a hardware reset.

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarRajkumar Manoharan <rmanohar@qti.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a899b678
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -374,6 +374,9 @@ struct ath_chanctx_sched {
	u32 switch_start_time;
	unsigned int offchannel_duration;
	unsigned int channel_switch_time;

	/* backup, in case the hardware timer fails */
	struct timer_list timer;
};

enum ath_offchannel_state {
@@ -426,6 +429,7 @@ struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
					      bool active);
void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
		       enum ath_chanctx_event ev);
void ath_chanctx_timer(unsigned long data);

int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan);
int ath_startrecv(struct ath_softc *sc);
+25 −7
Original line number Diff line number Diff line
@@ -469,6 +469,27 @@ static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc)
	prev->tsf_val += offset;
}

void ath_chanctx_timer(unsigned long data)
{
	struct ath_softc *sc = (struct ath_softc *) data;

	ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
}

/* Configure the TSF based hardware timer for a channel switch.
 * Also set up backup software timer, in case the gen timer fails.
 * This could be caused by a hardware reset.
 */
static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
{
	struct ath_hw *ah = sc->sc_ah;

	ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
	tsf_time -= ath9k_hw_gettsf32(ah);
	tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
	mod_timer(&sc->sched.timer, tsf_time);
}

void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
		       enum ath_chanctx_event ev)
{
@@ -566,9 +587,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
			break;

		sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
		ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer,
					 sc->sched.switch_start_time,
					 1000000);
		ath_chanctx_setup_timer(sc, sc->sched.switch_start_time);
		break;
	case ATH_CHANCTX_EVENT_TSF_TIMER:
		if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_TIMER)
@@ -598,8 +617,8 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
			ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL);
		tsf_time += ath9k_hw_gettsf32(ah);

		ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer,
					 tsf_time, 1000000);

		ath_chanctx_setup_timer(sc, tsf_time);
		break;
	case ATH_CHANCTX_EVENT_ASSOC:
		if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE ||
@@ -633,8 +652,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
		tsf_time += ath9k_hw_gettsf32(sc->sc_ah);
		sc->sched.switch_start_time = tsf_time;

		ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer,
					 tsf_time, 1000000);
		ath_chanctx_setup_timer(sc, tsf_time);
		sc->sched.beacon_pending = true;
		break;
	case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL:
+1 −0
Original line number Diff line number Diff line
@@ -569,6 +569,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
	INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
	setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
		    (unsigned long)sc);
	setup_timer(&sc->sched.timer, ath_chanctx_timer, (unsigned long)sc);

	/*
	 * Cache line size is used to size and align various
+1 −0
Original line number Diff line number Diff line
@@ -1668,6 +1668,7 @@ void ath9k_p2p_ps_timer(void *priv)
	struct ath_node *an;
	u32 tsf;

	del_timer_sync(&sc->sched.timer);
	ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer);
	ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);