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

Commit 5519541d authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville
Browse files

ath9k: fix powersave frame filtering/buffering in AP mode



This patch fixes a long standing issue of pending packets in the queue being
sent (and retransmitted many times) to sleeping stations.
This was made worse by aggregation through driver-internal retransmitting
of A-MDPU subframes.
Previously the hardware tx filter was cleared unconditionally for every
single packet - with this patch it uses the IEEE80211_TX_CTL_CLEAR_PS_FILT
for unaggregated frames.
A sta_notify driver op is added to stop aggregation for stations when they
enter powersave mode. Subframes stay buffered inside the driver, to ensure
that the BlockAck window keeps a sane state.
Since the driver uses software aggregation, the clearing of the tx filter
needs to be handled by the driver instead of mac80211 for aggregated frames.

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 8e22ad32
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
		| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
		| SM(txPower, AR_XmitPower)
		| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
		| (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
		| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
		| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);

@@ -311,6 +310,16 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
	}
}

static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
{
	struct ar5416_desc *ads = AR5416DESC(ds);

	if (val)
		ads->ds_ctl0 |= AR_ClrDestMask;
	else
		ads->ds_ctl0 &= ~AR_ClrDestMask;
}

static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
					  void *lastds,
					  u32 durUpdateEn, u32 rtsctsRate,
@@ -448,4 +457,5 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah)
	ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last;
	ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
	ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
	ops->set_clrdmask = ar9002_hw_set_clrdmask;
}
+11 −1
Original line number Diff line number Diff line
@@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
		| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
		| SM(txpower, AR_XmitPower)
		| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
		| (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
		| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
		| (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);

@@ -350,6 +349,16 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
	ads->ctl22 = 0;
}

static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
{
	struct ar9003_txc *ads = (struct ar9003_txc *) ds;

	if (val)
		ads->ctl11 |= AR_ClrDestMask;
	else
		ads->ctl11 &= ~AR_ClrDestMask;
}

static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
					  void *lastds,
					  u32 durUpdateEn, u32 rtsctsRate,
@@ -510,6 +519,7 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
	ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last;
	ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
	ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
	ops->set_clrdmask = ar9003_hw_set_clrdmask;
}

void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
+6 −0
Original line number Diff line number Diff line
@@ -200,6 +200,7 @@ struct ath_atx_ac {
	int sched;
	struct list_head list;
	struct list_head tid_q;
	bool clear_ps_filter;
};

struct ath_frame_info {
@@ -257,6 +258,8 @@ struct ath_node {
	struct ath_atx_ac ac[WME_NUM_AC];
	u16 maxampdu;
	u8 mpdudensity;

	bool sleeping;
};

#define AGGR_CLEANUP         BIT(1)
@@ -338,6 +341,9 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);

void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);

/********/
/* VIFs */
/********/
+5 −0
Original line number Diff line number Diff line
@@ -122,6 +122,11 @@ static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
	ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration);
}

static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
{
	ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
}

/* Private hardware call ops */

/* PHY ops */
+1 −0
Original line number Diff line number Diff line
@@ -626,6 +626,7 @@ struct ath_hw_ops {
	void (*clr11n_aggr)(struct ath_hw *ah, void *ds);
	void (*set11n_burstduration)(struct ath_hw *ah, void *ds,
				     u32 burstDuration);
	void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val);
};

struct ath_nf_limits {
Loading