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

Commit f4c88991 authored by Sujith Manoharan's avatar Sujith Manoharan Committed by John W. Linville
Browse files

ath9k_htc: Queue WMI events



Use a queue to handle WMI events and schedule a tasklet
to process the events. This fixes the race between the
WMI event ISR and the SWBA tasklet when the arrival of
WMI events in quick succession could overwrite the SWBA
data before the tasklet from a previous iteration could
have been scheduled. Also, drain the WMI queue properly.

Signed-off-by: default avatarSujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b0a6ba98
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -497,7 +497,8 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
			     struct ieee80211_vif *vif);
void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv);
void ath9k_htc_swba(struct ath9k_htc_priv *priv);
void ath9k_htc_swba(struct ath9k_htc_priv *priv,
		    struct wmi_event_swba *swba);

void ath9k_htc_rxep(void *priv, struct sk_buff *skb,
		    enum htc_endpoint_id ep_id);
+11 −16
Original line number Diff line number Diff line
@@ -401,10 +401,10 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
	spin_unlock_bh(&priv->beacon_lock);
}

static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv)
static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv,
				  struct wmi_event_swba *swba)
{
	struct ath_common *common = ath9k_hw_common(priv->ah);
	unsigned long flags;
	u64 tsf;
	u32 tsftu;
	u16 intval;
@@ -412,10 +412,7 @@ static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv)

	intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD;

	spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
	tsf = priv->wmi->tsf;
	spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);

	tsf = be64_to_cpu(swba->tsf);
	tsftu = TSF_TO_TU(tsf >> 32, tsf);
	slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval;
	slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1;
@@ -427,33 +424,31 @@ static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv)
	return slot;
}

void ath9k_htc_swba(struct ath9k_htc_priv *priv)
void ath9k_htc_swba(struct ath9k_htc_priv *priv,
		    struct wmi_event_swba *swba)
{
	struct ath_common *common = ath9k_hw_common(priv->ah);
	unsigned long flags;
	int slot;

	spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
	if (priv->wmi->beacon_pending != 0) {
		spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
	if (swba->beacon_pending != 0) {
		priv->cur_beacon_conf.bmiss_cnt++;
		if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) {
			ath_dbg(common, ATH_DBG_BEACON,
			ath_dbg(common, ATH_DBG_BSTUCK,
				"Beacon stuck, HW reset\n");
			ath9k_htc_reset(priv);
			ieee80211_queue_work(priv->hw,
					     &priv->fatal_work);
		}
		return;
	}
	spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);

	if (priv->cur_beacon_conf.bmiss_cnt) {
		ath_dbg(common, ATH_DBG_BEACON,
		ath_dbg(common, ATH_DBG_BSTUCK,
			"Resuming beacon xmit after %u misses\n",
			priv->cur_beacon_conf.bmiss_cnt);
		priv->cur_beacon_conf.bmiss_cnt = 0;
	}

	slot = ath9k_htc_choose_bslot(priv);
	slot = ath9k_htc_choose_bslot(priv, swba);
	spin_lock_bh(&priv->beacon_lock);
	if (priv->cur_beacon_conf.bslot[slot] == NULL) {
		spin_unlock_bh(&priv->beacon_lock);
+3 −0
Original line number Diff line number Diff line
@@ -436,6 +436,9 @@ void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
	/* Stop RX */
	WMI_CMD(WMI_STOP_RECV_CMDID);

	/* Clear the WMI event queue */
	ath9k_wmi_event_drain(priv);

	/*
	 * The MIB counters have to be disabled here,
	 * since the target doesn't do it.
+0 −2
Original line number Diff line number Diff line
@@ -676,8 +676,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
	spin_lock_init(&priv->tx_lock);
	mutex_init(&priv->mutex);
	mutex_init(&priv->htc_pm_lock);
	tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet,
		     (unsigned long)priv);
	tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
		     (unsigned long)priv);
	tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet,
+6 −1
Original line number Diff line number Diff line
@@ -202,6 +202,8 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
	WMI_CMD(WMI_STOP_RECV_CMDID);

	ath9k_wmi_event_drain(priv);

	caldata = &priv->caldata;
	ret = ath9k_hw_reset(ah, ah->curchan, caldata, false);
	if (ret) {
@@ -255,6 +257,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
	WMI_CMD(WMI_STOP_RECV_CMDID);

	ath9k_wmi_event_drain(priv);

	ath_dbg(common, ATH_DBG_CONFIG,
		"(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
		priv->ah->curchan->channel,
@@ -1172,12 +1176,13 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
	WMI_CMD(WMI_STOP_RECV_CMDID);

	tasklet_kill(&priv->swba_tasklet);
	tasklet_kill(&priv->rx_tasklet);
	tasklet_kill(&priv->tx_tasklet);

	skb_queue_purge(&priv->tx_queue);

	ath9k_wmi_event_drain(priv);

	mutex_unlock(&priv->mutex);

	/* Cancel all the running timers/work .. */
Loading