mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 05:54:26 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			312 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			312 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- a/drivers/net/wireless/ath/ath9k/ath9k.h
 | |
| +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
 | |
| @@ -202,6 +202,7 @@ struct ath_atx_ac {
 | |
|  	int sched;
 | |
|  	struct list_head list;
 | |
|  	struct list_head tid_q;
 | |
| +	bool clear_ps_filter;
 | |
|  };
 | |
|  
 | |
|  struct ath_frame_info {
 | |
| @@ -259,6 +260,8 @@ struct ath_node {
 | |
|  	struct ath_atx_ac ac[WME_NUM_AC];
 | |
|  	u16 maxampdu;
 | |
|  	u8 mpdudensity;
 | |
| +
 | |
| +	bool sleeping;
 | |
|  };
 | |
|  
 | |
|  #define AGGR_CLEANUP         BIT(1)
 | |
| @@ -340,6 +343,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
 | |
| @@ -1795,6 +1795,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)
 | |
|  {
 | |
| @@ -2197,6 +2218,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;
 | |
| @@ -546,7 +552,12 @@ static void ath_tx_complete_aggr(struct 
 | |
|  
 | |
|  	/* prepend un-acked frames to the beginning of the pending frame queue */
 | |
|  	if (!list_empty(&bf_pending)) {
 | |
| +		if (an->sleeping)
 | |
| +			ieee80211_sta_set_tim(sta);
 | |
| +
 | |
|  		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 +827,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 +912,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;
 | |
| @@ -1491,7 +1568,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)
 | |
| @@ -1754,6 +1830,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
 | |
| @@ -630,6 +630,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
 |