diff options
| -rw-r--r-- | package/mac80211/patches/530-mac80211_drv_tim_override.patch | 37 | ||||
| -rw-r--r-- | package/mac80211/patches/531-ath9k_fix_ap_ps_buffering.patch | 307 | 
2 files changed, 344 insertions, 0 deletions
diff --git a/package/mac80211/patches/530-mac80211_drv_tim_override.patch b/package/mac80211/patches/530-mac80211_drv_tim_override.patch new file mode 100644 index 000000000..e64d3aa83 --- /dev/null +++ b/package/mac80211/patches/530-mac80211_drv_tim_override.patch @@ -0,0 +1,37 @@ +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -2198,6 +2198,20 @@ static inline int ieee80211_sta_ps_trans + #define IEEE80211_TX_STATUS_HEADROOM	13 +  + /** ++ * ieee80211_sta_set_tim - set the TIM bit for a sleeping station ++ * ++ * If a driver buffers frames for a powersave station instead of passing ++ * them back to mac80211 for retransmission, the station needs to be told ++ * to wake up using the TIM bitmap in the beacon. ++ * ++ * This function sets the station's TIM bit - it will be cleared automatically ++ * either when the station wakes up (and mac80211 has flushed out its ++ * buffered frames), or if all remaining buffered frames in mac80211 have ++ * timed out. ++ */ ++void ieee80211_sta_set_tim(struct ieee80211_sta *sta); ++ ++/** +  * ieee80211_tx_status - transmit status callback +  * +  * Call this function for all transmitted frames after they have been +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -991,3 +991,11 @@ void ieee80211_sta_block_awake(struct ie + 		ieee80211_queue_work(hw, &sta->drv_unblock_wk); + } + EXPORT_SYMBOL(ieee80211_sta_block_awake); ++ ++void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta) ++{ ++	struct sta_info *sta = container_of(pubsta, struct sta_info, sta); ++ ++	sta_info_set_tim_bit(sta); ++} ++EXPORT_SYMBOL(ieee80211_sta_set_tim); diff --git a/package/mac80211/patches/531-ath9k_fix_ap_ps_buffering.patch b/package/mac80211/patches/531-ath9k_fix_ap_ps_buffering.patch new file mode 100644 index 000000000..7a9d9eaa0 --- /dev/null +++ b/package/mac80211/patches/531-ath9k_fix_ap_ps_buffering.patch @@ -0,0 +1,307 @@ +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -205,6 +205,7 @@ struct ath_atx_ac { + 	int sched; + 	struct list_head list; + 	struct list_head tid_q; ++	bool clear_ps_filter; + }; +  + struct ath_frame_info { +@@ -262,6 +263,8 @@ struct ath_node { + 	struct ath_atx_ac ac[WME_NUM_AC]; + 	u16 maxampdu; + 	u8 mpdudensity; ++ ++	bool sleeping; + }; +  + #define AGGR_CLEANUP         BIT(1) +@@ -343,6 +346,9 @@ int ath_tx_aggr_start(struct ath_softc * + 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 */ + /********/ +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -1791,6 +1791,27 @@ static int ath9k_sta_remove(struct ieee8 + 	return 0; + } +  ++static void ath9k_sta_notify(struct ieee80211_hw *hw, ++			 struct ieee80211_vif *vif, ++			 enum sta_notify_cmd cmd, ++			 struct ieee80211_sta *sta) ++{ ++	struct ath_softc *sc = hw->priv; ++	struct ath_node *an = (struct ath_node *) sta->drv_priv; ++ ++	switch (cmd) { ++	case STA_NOTIFY_SLEEP: ++		an->sleeping = true; ++		if (ath_tx_aggr_sleep(sc, an)) ++			ieee80211_sta_set_tim(sta); ++		break; ++	case STA_NOTIFY_AWAKE: ++		an->sleeping = false; ++		ath_tx_aggr_wakeup(sc, an); ++		break; ++	} ++} ++ + static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, + 			 const struct ieee80211_tx_queue_params *params) + { +@@ -2130,6 +2151,7 @@ struct ieee80211_ops ath9k_ops = { + 	.configure_filter   = ath9k_configure_filter, + 	.sta_add	    = ath9k_sta_add, + 	.sta_remove	    = ath9k_sta_remove, ++	.sta_notify         = ath9k_sta_notify, + 	.conf_tx 	    = ath9k_conf_tx, + 	.bss_info_changed   = ath9k_bss_info_changed, + 	.set_key            = ath9k_set_key, +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -357,6 +357,7 @@ static void ath_tx_complete_aggr(struct  + 	struct ath_frame_info *fi; + 	int nframes; + 	u8 tidno; ++	bool clear_filter; +  + 	skb = bf->bf_mpdu; + 	hdr = (struct ieee80211_hdr *)skb->data; +@@ -442,7 +443,11 @@ static void ath_tx_complete_aggr(struct  + 			acked_cnt++; + 		} else { + 			if (!(tid->state & AGGR_CLEANUP) && retry) { +-				if (fi->retries < ATH_MAX_SW_RETRIES) { ++				if (ts->ts_status & ATH9K_TXERR_FILT) { ++					if (!an->sleeping) ++						clear_filter = true; ++					txpending = 1; ++				} else if (fi->retries < ATH_MAX_SW_RETRIES) { + 					ath_tx_set_retry(sc, txq, bf->bf_mpdu); + 					txpending = 1; + 				} else { +@@ -496,6 +501,7 @@ static void ath_tx_complete_aggr(struct  + 				!txfail, sendbar); + 		} else { + 			/* retry the un-acked ones */ ++			ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false); + 			if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { + 				if (bf->bf_next == NULL && bf_last->bf_stale) { + 					struct ath_buf *tbf; +@@ -547,6 +553,8 @@ static void ath_tx_complete_aggr(struct  + 	/* prepend un-acked frames to the beginning of the pending frame queue */ + 	if (!list_empty(&bf_pending)) { + 		spin_lock_bh(&txq->axq_lock); ++		if (clear_filter) ++			tid->ac->clear_ps_filter = true; + 		list_splice(&bf_pending, &tid->buf_q); + 		ath_tx_queue_tid(txq, tid); + 		spin_unlock_bh(&txq->axq_lock); +@@ -816,6 +824,11 @@ static void ath_tx_sched_aggr(struct ath + 		bf = list_first_entry(&bf_q, struct ath_buf, list); + 		bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); +  ++		if (tid->ac->clear_ps_filter) { ++			tid->ac->clear_ps_filter = false; ++			ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); ++		} ++ + 		/* if only one frame, send as non-aggregate */ + 		if (bf == bf->bf_lastbf) { + 			fi = get_frame_info(bf->bf_mpdu); +@@ -896,6 +909,67 @@ void ath_tx_aggr_stop(struct ath_softc * + 	ath_tx_flush_tid(sc, txtid); + } +  ++bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) ++{ ++	struct ath_atx_tid *tid; ++	struct ath_atx_ac *ac; ++	struct ath_txq *txq; ++	bool buffered = false; ++	int tidno; ++ ++	for (tidno = 0, tid = &an->tid[tidno]; ++	     tidno < WME_NUM_TID; tidno++, tid++) { ++ ++		if (!tid->sched) ++			continue; ++ ++		ac = tid->ac; ++		txq = ac->txq; ++ ++		spin_lock_bh(&txq->axq_lock); ++ ++		if (!list_empty(&tid->buf_q)) ++			buffered = true; ++ ++		tid->sched = false; ++		list_del(&tid->list); ++ ++		if (ac->sched) { ++			ac->sched = false; ++			list_del(&ac->list); ++		} ++ ++		spin_unlock_bh(&txq->axq_lock); ++	} ++ ++	return buffered; ++} ++ ++void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) ++{ ++	struct ath_atx_tid *tid; ++	struct ath_atx_ac *ac; ++	struct ath_txq *txq; ++	int tidno; ++ ++	for (tidno = 0, tid = &an->tid[tidno]; ++	     tidno < WME_NUM_TID; tidno++, tid++) { ++ ++		ac = tid->ac; ++		txq = ac->txq; ++ ++		spin_lock_bh(&txq->axq_lock); ++		ac->clear_ps_filter = true; ++ ++		if (!list_empty(&tid->buf_q) && !tid->paused) { ++			ath_tx_queue_tid(txq, tid); ++			ath_txq_schedule(sc, txq); ++		} ++ ++		spin_unlock_bh(&txq->axq_lock); ++	} ++} ++ + void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) + { + 	struct ath_atx_tid *txtid; +@@ -1492,7 +1566,6 @@ static int setup_tx_flags(struct sk_buff + 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + 	int flags = 0; +  +-	flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ + 	flags |= ATH9K_TXDESC_INTREQ; +  + 	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) +@@ -1755,6 +1828,9 @@ static void ath_tx_start_dma(struct ath_ + 		if (txctl->paprd) + 			bf->bf_state.bfs_paprd_timestamp = jiffies; +  ++		if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) ++			ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); ++ + 		ath_tx_send_normal(sc, txctl->txq, tid, &bf_head); + 	} +  +--- a/drivers/net/wireless/ath/ath9k/hw-ops.h ++++ b/drivers/net/wireless/ath/ath9k/hw-ops.h +@@ -128,6 +128,11 @@ static inline void ath9k_hw_set11n_virtu + 	ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf); + } +  ++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 */ +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -642,6 +642,7 @@ struct ath_hw_ops { + 				     u32 burstDuration); + 	void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds, + 				       u32 vmf); ++	void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val); + }; +  + struct ath_nf_limits { +--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c ++++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c +@@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(stru + 		| (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(stru + 	} + } +  ++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, +@@ -460,4 +469,5 @@ void ar9002_hw_attach_mac_ops(struct ath + 	ops->clr11n_aggr = ar9002_hw_clr11n_aggr; + 	ops->set11n_burstduration = ar9002_hw_set11n_burstduration; + 	ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag; ++	ops->set_clrdmask = ar9002_hw_set_clrdmask; + } +--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c +@@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(stru + 		| (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(stru + 	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, +@@ -522,6 +531,7 @@ void ar9003_hw_attach_mac_ops(struct ath + 	ops->clr11n_aggr = ar9003_hw_clr11n_aggr; + 	ops->set11n_burstduration = ar9003_hw_set11n_burstduration; + 	ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag; ++	ops->set_clrdmask = ar9003_hw_set_clrdmask; + } +  + void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) +--- a/drivers/net/wireless/ath/ath9k/mac.h ++++ b/drivers/net/wireless/ath/ath9k/mac.h +@@ -239,7 +239,6 @@ struct ath_desc { + 	void *ds_vdata; + } __packed __aligned(4); +  +-#define ATH9K_TXDESC_CLRDMASK		0x0001 + #define ATH9K_TXDESC_NOACK		0x0002 + #define ATH9K_TXDESC_RTSENA		0x0004 + #define ATH9K_TXDESC_CTSENA		0x0008  | 
