ath9k: switch to using mac80211 intermediate software queues
Provides a nice latency reduction under load, due to mac80211's fq_codel support. Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
		| @@ -0,0 +1,871 @@ | |||||||
|  | From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk> | ||||||
|  | Date: Wed, 6 Jul 2016 21:34:17 +0200 | ||||||
|  | Subject: [PATCH] ath9k: Switch to using mac80211 intermediate software queues. | ||||||
|  | MIME-Version: 1.0 | ||||||
|  | Content-Type: text/plain; charset=UTF-8 | ||||||
|  | Content-Transfer-Encoding: 8bit | ||||||
|  |  | ||||||
|  | This switches ath9k over to using the mac80211 intermediate software | ||||||
|  | queueing mechanism for data packets. It removes the queueing inside the | ||||||
|  | driver, except for the retry queue, and instead pulls from mac80211 when | ||||||
|  | a packet is needed. The retry queue is used to store a packet that was | ||||||
|  | pulled but can't be sent immediately. | ||||||
|  |  | ||||||
|  | The old code path in ath_tx_start that would queue packets has been | ||||||
|  | removed completely, as has the qlen limit tunables (since there's no | ||||||
|  | longer a queue in the driver to limit). | ||||||
|  |  | ||||||
|  | Based on Tim's original patch set, but reworked quite thoroughly. | ||||||
|  |  | ||||||
|  | Cc: Tim Shepard <shep@alum.mit.edu> | ||||||
|  | Cc: Felix Fietkau <nbd@nbd.name> | ||||||
|  | Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | --- a/drivers/net/wireless/ath/ath9k/ath9k.h | ||||||
|  | +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | ||||||
|  | @@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc * | ||||||
|  |  #define ATH_RXBUF               512 | ||||||
|  |  #define ATH_TXBUF               512 | ||||||
|  |  #define ATH_TXBUF_RESERVE       5 | ||||||
|  | -#define ATH_MAX_QDEPTH          (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE) | ||||||
|  |  #define ATH_TXMAXTRY            13 | ||||||
|  |  #define ATH_MAX_SW_RETRIES      30 | ||||||
|  |   | ||||||
|  | @@ -145,7 +144,9 @@ int ath_descdma_setup(struct ath_softc * | ||||||
|  |  #define BAW_WITHIN(_start, _bawsz, _seqno) \ | ||||||
|  |  	((((_seqno) - (_start)) & 4095) < (_bawsz)) | ||||||
|  |   | ||||||
|  | -#define ATH_AN_2_TID(_an, _tidno)  (&(_an)->tid[(_tidno)]) | ||||||
|  | +#define ATH_STA_2_TID(_sta, _tidno) ((struct ath_atx_tid *)(_sta)->txq[_tidno]->drv_priv) | ||||||
|  | +#define ATH_VIF_2_TID(_vif) ((struct ath_atx_tid *)(_vif)->txq->drv_priv) | ||||||
|  | +#define ATH_AN_2_TID(_an, _tidno) ((_an)->sta ? ATH_STA_2_TID((_an)->sta, _tidno) : ATH_VIF_2_TID((_an)->vif)) | ||||||
|  |   | ||||||
|  |  #define IS_HT_RATE(rate)   (rate & 0x80) | ||||||
|  |  #define IS_CCK_RATE(rate)  ((rate >= 0x18) && (rate <= 0x1e)) | ||||||
|  | @@ -164,7 +165,6 @@ struct ath_txq { | ||||||
|  |  	spinlock_t axq_lock; | ||||||
|  |  	u32 axq_depth; | ||||||
|  |  	u32 axq_ampdu_depth; | ||||||
|  | -	bool stopped; | ||||||
|  |  	bool axq_tx_inprogress; | ||||||
|  |  	struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; | ||||||
|  |  	u8 txq_headidx; | ||||||
|  | @@ -232,7 +232,6 @@ struct ath_buf { | ||||||
|  |   | ||||||
|  |  struct ath_atx_tid { | ||||||
|  |  	struct list_head list; | ||||||
|  | -	struct sk_buff_head buf_q; | ||||||
|  |  	struct sk_buff_head retry_q; | ||||||
|  |  	struct ath_node *an; | ||||||
|  |  	struct ath_txq *txq; | ||||||
|  | @@ -247,13 +246,13 @@ struct ath_atx_tid { | ||||||
|  |  	s8 bar_index; | ||||||
|  |  	bool active; | ||||||
|  |  	bool clear_ps_filter; | ||||||
|  | +	bool has_queued; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  struct ath_node { | ||||||
|  |  	struct ath_softc *sc; | ||||||
|  |  	struct ieee80211_sta *sta; /* station struct we're part of */ | ||||||
|  |  	struct ieee80211_vif *vif; /* interface with which we're associated */ | ||||||
|  | -	struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; | ||||||
|  |   | ||||||
|  |  	u16 maxampdu; | ||||||
|  |  	u8 mpdudensity; | ||||||
|  | @@ -276,7 +275,6 @@ struct ath_tx_control { | ||||||
|  |  	struct ath_node *an; | ||||||
|  |  	struct ieee80211_sta *sta; | ||||||
|  |  	u8 paprd; | ||||||
|  | -	bool force_channel; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |   | ||||||
|  | @@ -293,7 +291,6 @@ struct ath_tx { | ||||||
|  |  	struct ath_descdma txdma; | ||||||
|  |  	struct ath_txq *txq_map[IEEE80211_NUM_ACS]; | ||||||
|  |  	struct ath_txq *uapsdq; | ||||||
|  | -	u32 txq_max_pending[IEEE80211_NUM_ACS]; | ||||||
|  |  	u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32]; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | @@ -585,6 +582,7 @@ void ath9k_release_buffered_frames(struc | ||||||
|  |  				   u16 tids, int nframes, | ||||||
|  |  				   enum ieee80211_frame_release_type reason, | ||||||
|  |  				   bool more_data); | ||||||
|  | +void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue); | ||||||
|  |   | ||||||
|  |  /********/ | ||||||
|  |  /* VIFs */ | ||||||
|  | --- a/drivers/net/wireless/ath/ath9k/channel.c | ||||||
|  | +++ b/drivers/net/wireless/ath/ath9k/channel.c | ||||||
|  | @@ -1007,7 +1007,6 @@ static void ath_scan_send_probe(struct a | ||||||
|  |  		goto error; | ||||||
|  |   | ||||||
|  |  	txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; | ||||||
|  | -	txctl.force_channel = true; | ||||||
|  |  	if (ath_tx_start(sc->hw, skb, &txctl)) | ||||||
|  |  		goto error; | ||||||
|  |   | ||||||
|  | @@ -1130,7 +1129,6 @@ ath_chanctx_send_vif_ps_frame(struct ath | ||||||
|  |  	memset(&txctl, 0, sizeof(txctl)); | ||||||
|  |  	txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; | ||||||
|  |  	txctl.sta = sta; | ||||||
|  | -	txctl.force_channel = true; | ||||||
|  |  	if (ath_tx_start(sc->hw, skb, &txctl)) { | ||||||
|  |  		ieee80211_free_txskb(sc->hw, skb); | ||||||
|  |  		return false; | ||||||
|  | --- a/drivers/net/wireless/ath/ath9k/debug.c | ||||||
|  | +++ b/drivers/net/wireless/ath/ath9k/debug.c | ||||||
|  | @@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_fil | ||||||
|  |  	PR("MPDUs XRetried:  ", xretries); | ||||||
|  |  	PR("Aggregates:      ", a_aggr); | ||||||
|  |  	PR("AMPDUs Queued HW:", a_queued_hw); | ||||||
|  | -	PR("AMPDUs Queued SW:", a_queued_sw); | ||||||
|  |  	PR("AMPDUs Completed:", a_completed); | ||||||
|  |  	PR("AMPDUs Retried:  ", a_retries); | ||||||
|  |  	PR("AMPDUs XRetried: ", a_xretries); | ||||||
|  | @@ -629,8 +628,7 @@ static void print_queue(struct ath_softc | ||||||
|  |  	seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum); | ||||||
|  |  	seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth); | ||||||
|  |  	seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth); | ||||||
|  | -	seq_printf(file, "%s: %3d ", "pending", txq->pending_frames); | ||||||
|  | -	seq_printf(file, "%s: %d\n", "stopped", txq->stopped); | ||||||
|  | +	seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames); | ||||||
|  |   | ||||||
|  |  	ath_txq_unlock(sc, txq); | ||||||
|  |  } | ||||||
|  | @@ -1208,7 +1206,6 @@ static const char ath9k_gstrings_stats[] | ||||||
|  |  	AMKSTR(d_tx_mpdu_xretries), | ||||||
|  |  	AMKSTR(d_tx_aggregates), | ||||||
|  |  	AMKSTR(d_tx_ampdus_queued_hw), | ||||||
|  | -	AMKSTR(d_tx_ampdus_queued_sw), | ||||||
|  |  	AMKSTR(d_tx_ampdus_completed), | ||||||
|  |  	AMKSTR(d_tx_ampdu_retries), | ||||||
|  |  	AMKSTR(d_tx_ampdu_xretries), | ||||||
|  | @@ -1288,7 +1285,6 @@ void ath9k_get_et_stats(struct ieee80211 | ||||||
|  |  	AWDATA(xretries); | ||||||
|  |  	AWDATA(a_aggr); | ||||||
|  |  	AWDATA(a_queued_hw); | ||||||
|  | -	AWDATA(a_queued_sw); | ||||||
|  |  	AWDATA(a_completed); | ||||||
|  |  	AWDATA(a_retries); | ||||||
|  |  	AWDATA(a_xretries); | ||||||
|  | @@ -1346,14 +1342,6 @@ int ath9k_init_debug(struct ath_hw *ah) | ||||||
|  |  				    read_file_xmit); | ||||||
|  |  	debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy, | ||||||
|  |  				    read_file_queues); | ||||||
|  | -	debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | ||||||
|  | -			   &sc->tx.txq_max_pending[IEEE80211_AC_BK]); | ||||||
|  | -	debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | ||||||
|  | -			   &sc->tx.txq_max_pending[IEEE80211_AC_BE]); | ||||||
|  | -	debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | ||||||
|  | -			   &sc->tx.txq_max_pending[IEEE80211_AC_VI]); | ||||||
|  | -	debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | ||||||
|  | -			   &sc->tx.txq_max_pending[IEEE80211_AC_VO]); | ||||||
|  |  	debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy, | ||||||
|  |  				    read_file_misc); | ||||||
|  |  	debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy, | ||||||
|  | --- a/drivers/net/wireless/ath/ath9k/debug.h | ||||||
|  | +++ b/drivers/net/wireless/ath/ath9k/debug.h | ||||||
|  | @@ -147,7 +147,6 @@ struct ath_interrupt_stats { | ||||||
|  |   * @completed: Total MPDUs (non-aggr) completed | ||||||
|  |   * @a_aggr: Total no. of aggregates queued | ||||||
|  |   * @a_queued_hw: Total AMPDUs queued to hardware | ||||||
|  | - * @a_queued_sw: Total AMPDUs queued to software queues | ||||||
|  |   * @a_completed: Total AMPDUs completed | ||||||
|  |   * @a_retries: No. of AMPDUs retried (SW) | ||||||
|  |   * @a_xretries: No. of AMPDUs dropped due to xretries | ||||||
|  | @@ -174,7 +173,6 @@ struct ath_tx_stats { | ||||||
|  |  	u32 xretries; | ||||||
|  |  	u32 a_aggr; | ||||||
|  |  	u32 a_queued_hw; | ||||||
|  | -	u32 a_queued_sw; | ||||||
|  |  	u32 a_completed; | ||||||
|  |  	u32 a_retries; | ||||||
|  |  	u32 a_xretries; | ||||||
|  | --- a/drivers/net/wireless/ath/ath9k/debug_sta.c | ||||||
|  | +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c | ||||||
|  | @@ -52,8 +52,8 @@ static ssize_t read_file_node_aggr(struc | ||||||
|  |  			 "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", | ||||||
|  |  			 "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED"); | ||||||
|  |   | ||||||
|  | -	for (tidno = 0, tid = &an->tid[tidno]; | ||||||
|  | -	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { | ||||||
|  | +	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { | ||||||
|  | +		tid = ATH_STA_2_TID(an->sta, tidno); | ||||||
|  |  		txq = tid->txq; | ||||||
|  |  		ath_txq_lock(sc, txq); | ||||||
|  |  		if (tid->active) { | ||||||
|  | --- a/drivers/net/wireless/ath/ath9k/init.c | ||||||
|  | +++ b/drivers/net/wireless/ath/ath9k/init.c | ||||||
|  | @@ -358,7 +358,6 @@ static int ath9k_init_queues(struct ath_ | ||||||
|  |  	for (i = 0; i < IEEE80211_NUM_ACS; i++) { | ||||||
|  |  		sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); | ||||||
|  |  		sc->tx.txq_map[i]->mac80211_qnum = i; | ||||||
|  | -		sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH; | ||||||
|  |  	} | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  | @@ -873,6 +872,7 @@ static void ath9k_set_hw_capab(struct at | ||||||
|  |  	hw->max_rate_tries = 10; | ||||||
|  |  	hw->sta_data_size = sizeof(struct ath_node); | ||||||
|  |  	hw->vif_data_size = sizeof(struct ath_vif); | ||||||
|  | +	hw->txq_data_size = sizeof(struct ath_atx_tid); | ||||||
|  |  	hw->extra_tx_headroom = 4; | ||||||
|  |   | ||||||
|  |  	hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; | ||||||
|  | --- a/drivers/net/wireless/ath/ath9k/main.c | ||||||
|  | +++ b/drivers/net/wireless/ath/ath9k/main.c | ||||||
|  | @@ -2695,4 +2695,5 @@ struct ieee80211_ops ath9k_ops = { | ||||||
|  |  	.sw_scan_start	    = ath9k_sw_scan_start, | ||||||
|  |  	.sw_scan_complete   = ath9k_sw_scan_complete, | ||||||
|  |  	.get_txpower        = ath9k_get_txpower, | ||||||
|  | +	.wake_tx_queue      = ath9k_wake_tx_queue, | ||||||
|  |  }; | ||||||
|  | --- a/drivers/net/wireless/ath/ath9k/xmit.c | ||||||
|  | +++ b/drivers/net/wireless/ath/ath9k/xmit.c | ||||||
|  | @@ -65,6 +65,8 @@ static struct ath_buf *ath_tx_setup_buff | ||||||
|  |  					   struct ath_txq *txq, | ||||||
|  |  					   struct ath_atx_tid *tid, | ||||||
|  |  					   struct sk_buff *skb); | ||||||
|  | +static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, | ||||||
|  | +			  struct ath_tx_control *txctl); | ||||||
|  |   | ||||||
|  |  enum { | ||||||
|  |  	MCS_HT20, | ||||||
|  | @@ -118,6 +120,26 @@ static void ath_tx_queue_tid(struct ath_ | ||||||
|  |  		list_add_tail(&tid->list, list); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue) | ||||||
|  | +{ | ||||||
|  | +	struct ath_softc *sc = hw->priv; | ||||||
|  | +	struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||||||
|  | +	struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv; | ||||||
|  | +	struct ath_txq *txq = tid->txq; | ||||||
|  | + | ||||||
|  | +	ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n", | ||||||
|  | +		queue->sta ? queue->sta->addr : queue->vif->addr, | ||||||
|  | +		tid->tidno); | ||||||
|  | + | ||||||
|  | +	ath_txq_lock(sc, txq); | ||||||
|  | + | ||||||
|  | +	tid->has_queued = true; | ||||||
|  | +	ath_tx_queue_tid(sc, txq, tid); | ||||||
|  | +	ath_txq_schedule(sc, txq); | ||||||
|  | + | ||||||
|  | +	ath_txq_unlock(sc, txq); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static struct ath_frame_info *get_frame_info(struct sk_buff *skb) | ||||||
|  |  { | ||||||
|  |  	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||||||
|  | @@ -160,7 +182,6 @@ static void ath_set_rates(struct ieee802 | ||||||
|  |  static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, | ||||||
|  |  			     struct sk_buff *skb) | ||||||
|  |  { | ||||||
|  | -	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||||
|  |  	struct ath_frame_info *fi = get_frame_info(skb); | ||||||
|  |  	int q = fi->txq; | ||||||
|  |   | ||||||
|  | @@ -171,14 +192,6 @@ static void ath_txq_skb_done(struct ath_ | ||||||
|  |  	if (WARN_ON(--txq->pending_frames < 0)) | ||||||
|  |  		txq->pending_frames = 0; | ||||||
|  |   | ||||||
|  | -	if (txq->stopped && | ||||||
|  | -	    txq->pending_frames < sc->tx.txq_max_pending[q]) { | ||||||
|  | -		if (ath9k_is_chanctx_enabled()) | ||||||
|  | -			ieee80211_wake_queue(sc->hw, info->hw_queue); | ||||||
|  | -		else | ||||||
|  | -			ieee80211_wake_queue(sc->hw, q); | ||||||
|  | -		txq->stopped = false; | ||||||
|  | -	} | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static struct ath_atx_tid * | ||||||
|  | @@ -188,9 +201,47 @@ ath_get_skb_tid(struct ath_softc *sc, st | ||||||
|  |  	return ATH_AN_2_TID(an, tidno); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static struct sk_buff * | ||||||
|  | +ath_tid_pull(struct ath_atx_tid *tid) | ||||||
|  | +{ | ||||||
|  | +	struct ath_softc *sc = tid->an->sc; | ||||||
|  | +	struct ieee80211_hw *hw = sc->hw; | ||||||
|  | +	struct ath_tx_control txctl = { | ||||||
|  | +		.txq = tid->txq, | ||||||
|  | +		.sta = tid->an->sta, | ||||||
|  | +	}; | ||||||
|  | +	struct sk_buff *skb; | ||||||
|  | +	struct ath_frame_info *fi; | ||||||
|  | +	int q; | ||||||
|  | + | ||||||
|  | +	if (!tid->has_queued) | ||||||
|  | +		return NULL; | ||||||
|  | + | ||||||
|  | +	skb = ieee80211_tx_dequeue(hw, container_of((void*)tid, struct ieee80211_txq, drv_priv)); | ||||||
|  | +	if (!skb) { | ||||||
|  | +		tid->has_queued = false; | ||||||
|  | +		return NULL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (ath_tx_prepare(hw, skb, &txctl)) { | ||||||
|  | +		ieee80211_free_txskb(hw, skb); | ||||||
|  | +		return NULL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	q = skb_get_queue_mapping(skb); | ||||||
|  | +	if (tid->txq == sc->tx.txq_map[q]) { | ||||||
|  | +		fi = get_frame_info(skb); | ||||||
|  | +		fi->txq = q; | ||||||
|  | +		++tid->txq->pending_frames; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return skb; | ||||||
|  | + } | ||||||
|  | + | ||||||
|  | + | ||||||
|  |  static bool ath_tid_has_buffered(struct ath_atx_tid *tid) | ||||||
|  |  { | ||||||
|  | -	return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q); | ||||||
|  | +	return !skb_queue_empty(&tid->retry_q) || tid->has_queued; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) | ||||||
|  | @@ -199,46 +250,11 @@ static struct sk_buff *ath_tid_dequeue(s | ||||||
|  |   | ||||||
|  |  	skb = __skb_dequeue(&tid->retry_q); | ||||||
|  |  	if (!skb) | ||||||
|  | -		skb = __skb_dequeue(&tid->buf_q); | ||||||
|  | +		skb = ath_tid_pull(tid); | ||||||
|  |   | ||||||
|  |  	return skb; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -/* | ||||||
|  | - * ath_tx_tid_change_state: | ||||||
|  | - * - clears a-mpdu flag of previous session | ||||||
|  | - * - force sequence number allocation to fix next BlockAck Window | ||||||
|  | - */ | ||||||
|  | -static void | ||||||
|  | -ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid) | ||||||
|  | -{ | ||||||
|  | -	struct ath_txq *txq = tid->txq; | ||||||
|  | -	struct ieee80211_tx_info *tx_info; | ||||||
|  | -	struct sk_buff *skb, *tskb; | ||||||
|  | -	struct ath_buf *bf; | ||||||
|  | -	struct ath_frame_info *fi; | ||||||
|  | - | ||||||
|  | -	skb_queue_walk_safe(&tid->buf_q, skb, tskb) { | ||||||
|  | -		fi = get_frame_info(skb); | ||||||
|  | -		bf = fi->bf; | ||||||
|  | - | ||||||
|  | -		tx_info = IEEE80211_SKB_CB(skb); | ||||||
|  | -		tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU; | ||||||
|  | - | ||||||
|  | -		if (bf) | ||||||
|  | -			continue; | ||||||
|  | - | ||||||
|  | -		bf = ath_tx_setup_buffer(sc, txq, tid, skb); | ||||||
|  | -		if (!bf) { | ||||||
|  | -			__skb_unlink(skb, &tid->buf_q); | ||||||
|  | -			ath_txq_skb_done(sc, txq, skb); | ||||||
|  | -			ieee80211_free_txskb(sc->hw, skb); | ||||||
|  | -			continue; | ||||||
|  | -		} | ||||||
|  | -	} | ||||||
|  | - | ||||||
|  | -} | ||||||
|  | - | ||||||
|  |  static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) | ||||||
|  |  { | ||||||
|  |  	struct ath_txq *txq = tid->txq; | ||||||
|  | @@ -873,20 +889,16 @@ static int ath_compute_num_delims(struct | ||||||
|  |   | ||||||
|  |  static struct ath_buf * | ||||||
|  |  ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, | ||||||
|  | -			struct ath_atx_tid *tid, struct sk_buff_head **q) | ||||||
|  | +			struct ath_atx_tid *tid) | ||||||
|  |  { | ||||||
|  |  	struct ieee80211_tx_info *tx_info; | ||||||
|  |  	struct ath_frame_info *fi; | ||||||
|  | -	struct sk_buff *skb; | ||||||
|  | +	struct sk_buff *skb, *first_skb = NULL; | ||||||
|  |  	struct ath_buf *bf; | ||||||
|  |  	u16 seqno; | ||||||
|  |   | ||||||
|  |  	while (1) { | ||||||
|  | -		*q = &tid->retry_q; | ||||||
|  | -		if (skb_queue_empty(*q)) | ||||||
|  | -			*q = &tid->buf_q; | ||||||
|  | - | ||||||
|  | -		skb = skb_peek(*q); | ||||||
|  | +		skb = ath_tid_dequeue(tid); | ||||||
|  |  		if (!skb) | ||||||
|  |  			break; | ||||||
|  |   | ||||||
|  | @@ -898,7 +910,6 @@ ath_tx_get_tid_subframe(struct ath_softc | ||||||
|  |  			bf->bf_state.stale = false; | ||||||
|  |   | ||||||
|  |  		if (!bf) { | ||||||
|  | -			__skb_unlink(skb, *q); | ||||||
|  |  			ath_txq_skb_done(sc, txq, skb); | ||||||
|  |  			ieee80211_free_txskb(sc->hw, skb); | ||||||
|  |  			continue; | ||||||
|  | @@ -927,8 +938,19 @@ ath_tx_get_tid_subframe(struct ath_softc | ||||||
|  |  		seqno = bf->bf_state.seqno; | ||||||
|  |   | ||||||
|  |  		/* do not step over block-ack window */ | ||||||
|  | -		if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) | ||||||
|  | +		if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { | ||||||
|  | +			__skb_queue_tail(&tid->retry_q, skb); | ||||||
|  | + | ||||||
|  | +			/* If there are other skbs in the retry q, they are | ||||||
|  | +			 * probably within the BAW, so loop immediately to get | ||||||
|  | +			 * one of them. Otherwise the queue can get stuck. */ | ||||||
|  | +			if (!skb_queue_is_first(&tid->retry_q, skb) && skb != first_skb) { | ||||||
|  | +				if(!first_skb) /* infinite loop prevention */ | ||||||
|  | +					first_skb = skb; | ||||||
|  | +				continue; | ||||||
|  | +			} | ||||||
|  |  			break; | ||||||
|  | +		} | ||||||
|  |   | ||||||
|  |  		if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) { | ||||||
|  |  			struct ath_tx_status ts = {}; | ||||||
|  | @@ -936,7 +958,6 @@ ath_tx_get_tid_subframe(struct ath_softc | ||||||
|  |   | ||||||
|  |  			INIT_LIST_HEAD(&bf_head); | ||||||
|  |  			list_add(&bf->list, &bf_head); | ||||||
|  | -			__skb_unlink(skb, *q); | ||||||
|  |  			ath_tx_update_baw(sc, tid, seqno); | ||||||
|  |  			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); | ||||||
|  |  			continue; | ||||||
|  | @@ -948,11 +969,10 @@ ath_tx_get_tid_subframe(struct ath_softc | ||||||
|  |  	return NULL; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -static bool | ||||||
|  | +static int | ||||||
|  |  ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq, | ||||||
|  |  		 struct ath_atx_tid *tid, struct list_head *bf_q, | ||||||
|  | -		 struct ath_buf *bf_first, struct sk_buff_head *tid_q, | ||||||
|  | -		 int *aggr_len) | ||||||
|  | +		 struct ath_buf *bf_first) | ||||||
|  |  { | ||||||
|  |  #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) | ||||||
|  |  	struct ath_buf *bf = bf_first, *bf_prev = NULL; | ||||||
|  | @@ -962,12 +982,13 @@ ath_tx_form_aggr(struct ath_softc *sc, s | ||||||
|  |  	struct ieee80211_tx_info *tx_info; | ||||||
|  |  	struct ath_frame_info *fi; | ||||||
|  |  	struct sk_buff *skb; | ||||||
|  | -	bool closed = false; | ||||||
|  | + | ||||||
|  |   | ||||||
|  |  	bf = bf_first; | ||||||
|  |  	aggr_limit = ath_lookup_rate(sc, bf, tid); | ||||||
|  |   | ||||||
|  | -	do { | ||||||
|  | +	while (bf) | ||||||
|  | +	{ | ||||||
|  |  		skb = bf->bf_mpdu; | ||||||
|  |  		fi = get_frame_info(skb); | ||||||
|  |   | ||||||
|  | @@ -976,12 +997,12 @@ ath_tx_form_aggr(struct ath_softc *sc, s | ||||||
|  |  		if (nframes) { | ||||||
|  |  			if (aggr_limit < al + bpad + al_delta || | ||||||
|  |  			    ath_lookup_legacy(bf) || nframes >= h_baw) | ||||||
|  | -				break; | ||||||
|  | +				goto stop; | ||||||
|  |   | ||||||
|  |  			tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); | ||||||
|  |  			if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) || | ||||||
|  |  			    !(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) | ||||||
|  | -				break; | ||||||
|  | +				goto stop; | ||||||
|  |  		} | ||||||
|  |   | ||||||
|  |  		/* add padding for previous frame to aggregation length */ | ||||||
|  | @@ -1003,20 +1024,18 @@ ath_tx_form_aggr(struct ath_softc *sc, s | ||||||
|  |  			ath_tx_addto_baw(sc, tid, bf); | ||||||
|  |  		bf->bf_state.ndelim = ndelim; | ||||||
|  |   | ||||||
|  | -		__skb_unlink(skb, tid_q); | ||||||
|  |  		list_add_tail(&bf->list, bf_q); | ||||||
|  |  		if (bf_prev) | ||||||
|  |  			bf_prev->bf_next = bf; | ||||||
|  |   | ||||||
|  |  		bf_prev = bf; | ||||||
|  |   | ||||||
|  | -		bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); | ||||||
|  | -		if (!bf) { | ||||||
|  | -			closed = true; | ||||||
|  | -			break; | ||||||
|  | -		} | ||||||
|  | -	} while (ath_tid_has_buffered(tid)); | ||||||
|  | - | ||||||
|  | +		bf = ath_tx_get_tid_subframe(sc, txq, tid); | ||||||
|  | +	} | ||||||
|  | +	goto finish; | ||||||
|  | +stop: | ||||||
|  | +	__skb_queue_tail(&tid->retry_q, bf->bf_mpdu); | ||||||
|  | +finish: | ||||||
|  |  	bf = bf_first; | ||||||
|  |  	bf->bf_lastbf = bf_prev; | ||||||
|  |   | ||||||
|  | @@ -1027,9 +1046,7 @@ ath_tx_form_aggr(struct ath_softc *sc, s | ||||||
|  |  		TX_STAT_INC(txq->axq_qnum, a_aggr); | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -	*aggr_len = al; | ||||||
|  | - | ||||||
|  | -	return closed; | ||||||
|  | +	return al; | ||||||
|  |  #undef PADBYTES | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | @@ -1406,18 +1423,15 @@ static void ath_tx_fill_desc(struct ath_ | ||||||
|  |  static void | ||||||
|  |  ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq, | ||||||
|  |  		  struct ath_atx_tid *tid, struct list_head *bf_q, | ||||||
|  | -		  struct ath_buf *bf_first, struct sk_buff_head *tid_q) | ||||||
|  | +		  struct ath_buf *bf_first) | ||||||
|  |  { | ||||||
|  |  	struct ath_buf *bf = bf_first, *bf_prev = NULL; | ||||||
|  | -	struct sk_buff *skb; | ||||||
|  |  	int nframes = 0; | ||||||
|  |   | ||||||
|  |  	do { | ||||||
|  |  		struct ieee80211_tx_info *tx_info; | ||||||
|  | -		skb = bf->bf_mpdu; | ||||||
|  |   | ||||||
|  |  		nframes++; | ||||||
|  | -		__skb_unlink(skb, tid_q); | ||||||
|  |  		list_add_tail(&bf->list, bf_q); | ||||||
|  |  		if (bf_prev) | ||||||
|  |  			bf_prev->bf_next = bf; | ||||||
|  | @@ -1426,13 +1440,15 @@ ath_tx_form_burst(struct ath_softc *sc, | ||||||
|  |  		if (nframes >= 2) | ||||||
|  |  			break; | ||||||
|  |   | ||||||
|  | -		bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); | ||||||
|  | +		bf = ath_tx_get_tid_subframe(sc, txq, tid); | ||||||
|  |  		if (!bf) | ||||||
|  |  			break; | ||||||
|  |   | ||||||
|  |  		tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); | ||||||
|  | -		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) | ||||||
|  | +		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { | ||||||
|  | +			__skb_queue_tail(&tid->retry_q, bf->bf_mpdu); | ||||||
|  |  			break; | ||||||
|  | +		} | ||||||
|  |   | ||||||
|  |  		ath_set_rates(tid->an->vif, tid->an->sta, bf, false); | ||||||
|  |  	} while (1); | ||||||
|  | @@ -1443,34 +1459,33 @@ static bool ath_tx_sched_aggr(struct ath | ||||||
|  |  { | ||||||
|  |  	struct ath_buf *bf; | ||||||
|  |  	struct ieee80211_tx_info *tx_info; | ||||||
|  | -	struct sk_buff_head *tid_q; | ||||||
|  |  	struct list_head bf_q; | ||||||
|  |  	int aggr_len = 0; | ||||||
|  | -	bool aggr, last = true; | ||||||
|  | +	bool aggr; | ||||||
|  |   | ||||||
|  |  	if (!ath_tid_has_buffered(tid)) | ||||||
|  |  		return false; | ||||||
|  |   | ||||||
|  |  	INIT_LIST_HEAD(&bf_q); | ||||||
|  |   | ||||||
|  | -	bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); | ||||||
|  | +	bf = ath_tx_get_tid_subframe(sc, txq, tid); | ||||||
|  |  	if (!bf) | ||||||
|  |  		return false; | ||||||
|  |   | ||||||
|  |  	tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); | ||||||
|  |  	aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); | ||||||
|  |  	if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || | ||||||
|  | -		(!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { | ||||||
|  | +	    (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { | ||||||
|  | +		__skb_queue_tail(&tid->retry_q, bf->bf_mpdu); | ||||||
|  |  		*stop = true; | ||||||
|  |  		return false; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  |  	ath_set_rates(tid->an->vif, tid->an->sta, bf, false); | ||||||
|  |  	if (aggr) | ||||||
|  | -		last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf, | ||||||
|  | -					tid_q, &aggr_len); | ||||||
|  | +		aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf); | ||||||
|  |  	else | ||||||
|  | -		ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q); | ||||||
|  | +		ath_tx_form_burst(sc, txq, tid, &bf_q, bf); | ||||||
|  |   | ||||||
|  |  	if (list_empty(&bf_q)) | ||||||
|  |  		return false; | ||||||
|  | @@ -1513,9 +1528,6 @@ int ath_tx_aggr_start(struct ath_softc * | ||||||
|  |  		an->mpdudensity = density; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -	/* force sequence number allocation for pending frames */ | ||||||
|  | -	ath_tx_tid_change_state(sc, txtid); | ||||||
|  | - | ||||||
|  |  	txtid->active = true; | ||||||
|  |  	*ssn = txtid->seq_start = txtid->seq_next; | ||||||
|  |  	txtid->bar_index = -1; | ||||||
|  | @@ -1540,7 +1552,6 @@ void ath_tx_aggr_stop(struct ath_softc * | ||||||
|  |  	ath_txq_lock(sc, txq); | ||||||
|  |  	txtid->active = false; | ||||||
|  |  	ath_tx_flush_tid(sc, txtid); | ||||||
|  | -	ath_tx_tid_change_state(sc, txtid); | ||||||
|  |  	ath_txq_unlock_complete(sc, txq); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | @@ -1550,14 +1561,12 @@ void ath_tx_aggr_sleep(struct ieee80211_ | ||||||
|  |  	struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||||||
|  |  	struct ath_atx_tid *tid; | ||||||
|  |  	struct ath_txq *txq; | ||||||
|  | -	bool buffered; | ||||||
|  |  	int tidno; | ||||||
|  |   | ||||||
|  |  	ath_dbg(common, XMIT, "%s called\n", __func__); | ||||||
|  |   | ||||||
|  | -	for (tidno = 0, tid = &an->tid[tidno]; | ||||||
|  | -	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { | ||||||
|  | - | ||||||
|  | +	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { | ||||||
|  | +		tid = ATH_AN_2_TID(an, tidno); | ||||||
|  |  		txq = tid->txq; | ||||||
|  |   | ||||||
|  |  		ath_txq_lock(sc, txq); | ||||||
|  | @@ -1567,13 +1576,12 @@ void ath_tx_aggr_sleep(struct ieee80211_ | ||||||
|  |  			continue; | ||||||
|  |  		} | ||||||
|  |   | ||||||
|  | -		buffered = ath_tid_has_buffered(tid); | ||||||
|  | +		if (!skb_queue_empty(&tid->retry_q)) | ||||||
|  | +			ieee80211_sta_set_buffered(sta, tid->tidno, true); | ||||||
|  |   | ||||||
|  |  		list_del_init(&tid->list); | ||||||
|  |   | ||||||
|  |  		ath_txq_unlock(sc, txq); | ||||||
|  | - | ||||||
|  | -		ieee80211_sta_set_buffered(sta, tidno, buffered); | ||||||
|  |  	} | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | @@ -1586,19 +1594,16 @@ void ath_tx_aggr_wakeup(struct ath_softc | ||||||
|  |   | ||||||
|  |  	ath_dbg(common, XMIT, "%s called\n", __func__); | ||||||
|  |   | ||||||
|  | -	for (tidno = 0, tid = &an->tid[tidno]; | ||||||
|  | -	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { | ||||||
|  | - | ||||||
|  | +	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { | ||||||
|  | +		tid = ATH_AN_2_TID(an, tidno); | ||||||
|  |  		txq = tid->txq; | ||||||
|  |   | ||||||
|  |  		ath_txq_lock(sc, txq); | ||||||
|  |  		tid->clear_ps_filter = true; | ||||||
|  | - | ||||||
|  |  		if (ath_tid_has_buffered(tid)) { | ||||||
|  |  			ath_tx_queue_tid(sc, txq, tid); | ||||||
|  |  			ath_txq_schedule(sc, txq); | ||||||
|  |  		} | ||||||
|  | - | ||||||
|  |  		ath_txq_unlock_complete(sc, txq); | ||||||
|  |  	} | ||||||
|  |  } | ||||||
|  | @@ -1621,11 +1626,6 @@ void ath_tx_aggr_resume(struct ath_softc | ||||||
|  |   | ||||||
|  |  	tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; | ||||||
|  |   | ||||||
|  | -	if (ath_tid_has_buffered(tid)) { | ||||||
|  | -		ath_tx_queue_tid(sc, txq, tid); | ||||||
|  | -		ath_txq_schedule(sc, txq); | ||||||
|  | -	} | ||||||
|  | - | ||||||
|  |  	ath_txq_unlock_complete(sc, txq); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | @@ -1641,7 +1641,6 @@ void ath9k_release_buffered_frames(struc | ||||||
|  |  	struct ieee80211_tx_info *info; | ||||||
|  |  	struct list_head bf_q; | ||||||
|  |  	struct ath_buf *bf_tail = NULL, *bf; | ||||||
|  | -	struct sk_buff_head *tid_q; | ||||||
|  |  	int sent = 0; | ||||||
|  |  	int i; | ||||||
|  |   | ||||||
|  | @@ -1656,11 +1655,10 @@ void ath9k_release_buffered_frames(struc | ||||||
|  |   | ||||||
|  |  		ath_txq_lock(sc, tid->txq); | ||||||
|  |  		while (nframes > 0) { | ||||||
|  | -			bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q); | ||||||
|  | +			bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid); | ||||||
|  |  			if (!bf) | ||||||
|  |  				break; | ||||||
|  |   | ||||||
|  | -			__skb_unlink(bf->bf_mpdu, tid_q); | ||||||
|  |  			list_add_tail(&bf->list, &bf_q); | ||||||
|  |  			ath_set_rates(tid->an->vif, tid->an->sta, bf, true); | ||||||
|  |  			if (bf_isampdu(bf)) { | ||||||
|  | @@ -1675,7 +1673,7 @@ void ath9k_release_buffered_frames(struc | ||||||
|  |  			sent++; | ||||||
|  |  			TX_STAT_INC(txq->axq_qnum, a_queued_hw); | ||||||
|  |   | ||||||
|  | -			if (an->sta && !ath_tid_has_buffered(tid)) | ||||||
|  | +			if (an->sta && skb_queue_empty(&tid->retry_q)) | ||||||
|  |  				ieee80211_sta_set_buffered(an->sta, i, false); | ||||||
|  |  		} | ||||||
|  |  		ath_txq_unlock_complete(sc, tid->txq); | ||||||
|  | @@ -1902,13 +1900,7 @@ bool ath_drain_all_txq(struct ath_softc | ||||||
|  |  		if (!ATH_TXQ_SETUP(sc, i)) | ||||||
|  |  			continue; | ||||||
|  |   | ||||||
|  | -		/* | ||||||
|  | -		 * The caller will resume queues with ieee80211_wake_queues. | ||||||
|  | -		 * Mark the queue as not stopped to prevent ath_tx_complete | ||||||
|  | -		 * from waking the queue too early. | ||||||
|  | -		 */ | ||||||
|  |  		txq = &sc->tx.txq[i]; | ||||||
|  | -		txq->stopped = false; | ||||||
|  |  		ath_draintxq(sc, txq); | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | @@ -2308,15 +2300,12 @@ int ath_tx_start(struct ieee80211_hw *hw | ||||||
|  |  	struct ath_txq *txq = txctl->txq; | ||||||
|  |  	struct ath_atx_tid *tid = NULL; | ||||||
|  |  	struct ath_buf *bf; | ||||||
|  | -	bool queue, ps_resp; | ||||||
|  | +	bool ps_resp; | ||||||
|  |  	int q, ret; | ||||||
|  |   | ||||||
|  |  	if (vif) | ||||||
|  |  		avp = (void *)vif->drv_priv; | ||||||
|  |   | ||||||
|  | -	if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) | ||||||
|  | -		txctl->force_channel = true; | ||||||
|  | - | ||||||
|  |  	ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE); | ||||||
|  |   | ||||||
|  |  	ret = ath_tx_prepare(hw, skb, txctl); | ||||||
|  | @@ -2331,63 +2320,13 @@ int ath_tx_start(struct ieee80211_hw *hw | ||||||
|  |   | ||||||
|  |  	q = skb_get_queue_mapping(skb); | ||||||
|  |   | ||||||
|  | +	if (ps_resp) | ||||||
|  | +		txq = sc->tx.uapsdq; | ||||||
|  | + | ||||||
|  |  	ath_txq_lock(sc, txq); | ||||||
|  |  	if (txq == sc->tx.txq_map[q]) { | ||||||
|  |  		fi->txq = q; | ||||||
|  | -		if (++txq->pending_frames > sc->tx.txq_max_pending[q] && | ||||||
|  | -		    !txq->stopped) { | ||||||
|  | -			if (ath9k_is_chanctx_enabled()) | ||||||
|  | -				ieee80211_stop_queue(sc->hw, info->hw_queue); | ||||||
|  | -			else | ||||||
|  | -				ieee80211_stop_queue(sc->hw, q); | ||||||
|  | -			txq->stopped = true; | ||||||
|  | -		} | ||||||
|  | -	} | ||||||
|  | - | ||||||
|  | -	queue = ieee80211_is_data_present(hdr->frame_control); | ||||||
|  | - | ||||||
|  | -	/* If chanctx, queue all null frames while NOA could be there */ | ||||||
|  | -	if (ath9k_is_chanctx_enabled() && | ||||||
|  | -	    ieee80211_is_nullfunc(hdr->frame_control) && | ||||||
|  | -	    !txctl->force_channel) | ||||||
|  | -		queue = true; | ||||||
|  | - | ||||||
|  | -	/* Force queueing of all frames that belong to a virtual interface on | ||||||
|  | -	 * a different channel context, to ensure that they are sent on the | ||||||
|  | -	 * correct channel. | ||||||
|  | -	 */ | ||||||
|  | -	if (((avp && avp->chanctx != sc->cur_chan) || | ||||||
|  | -	     sc->cur_chan->stopped) && !txctl->force_channel) { | ||||||
|  | -		if (!txctl->an) | ||||||
|  | -			txctl->an = &avp->mcast_node; | ||||||
|  | -		queue = true; | ||||||
|  | -		ps_resp = false; | ||||||
|  | -	} | ||||||
|  | - | ||||||
|  | -	if (txctl->an && queue) | ||||||
|  | -		tid = ath_get_skb_tid(sc, txctl->an, skb); | ||||||
|  | - | ||||||
|  | -	if (ps_resp) { | ||||||
|  | -		ath_txq_unlock(sc, txq); | ||||||
|  | -		txq = sc->tx.uapsdq; | ||||||
|  | -		ath_txq_lock(sc, txq); | ||||||
|  | -	} else if (txctl->an && queue) { | ||||||
|  | -		WARN_ON(tid->txq != txctl->txq); | ||||||
|  | - | ||||||
|  | -		if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) | ||||||
|  | -			tid->clear_ps_filter = true; | ||||||
|  | - | ||||||
|  | -		/* | ||||||
|  | -		 * Add this frame to software queue for scheduling later | ||||||
|  | -		 * for aggregation. | ||||||
|  | -		 */ | ||||||
|  | -		TX_STAT_INC(txq->axq_qnum, a_queued_sw); | ||||||
|  | -		__skb_queue_tail(&tid->buf_q, skb); | ||||||
|  | -		if (!txctl->an->sleeping) | ||||||
|  | -			ath_tx_queue_tid(sc, txq, tid); | ||||||
|  | - | ||||||
|  | -		ath_txq_schedule(sc, txq); | ||||||
|  | -		goto out; | ||||||
|  | +		++txq->pending_frames; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  |  	bf = ath_tx_setup_buffer(sc, txq, tid, skb); | ||||||
|  | @@ -2871,9 +2810,8 @@ void ath_tx_node_init(struct ath_softc * | ||||||
|  |  	struct ath_atx_tid *tid; | ||||||
|  |  	int tidno, acno; | ||||||
|  |   | ||||||
|  | -	for (tidno = 0, tid = &an->tid[tidno]; | ||||||
|  | -	     tidno < IEEE80211_NUM_TIDS; | ||||||
|  | -	     tidno++, tid++) { | ||||||
|  | +	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { | ||||||
|  | +		tid = ATH_AN_2_TID(an, tidno); | ||||||
|  |  		tid->an        = an; | ||||||
|  |  		tid->tidno     = tidno; | ||||||
|  |  		tid->seq_start = tid->seq_next = 0; | ||||||
|  | @@ -2881,11 +2819,14 @@ void ath_tx_node_init(struct ath_softc * | ||||||
|  |  		tid->baw_head  = tid->baw_tail = 0; | ||||||
|  |  		tid->active	   = false; | ||||||
|  |  		tid->clear_ps_filter = true; | ||||||
|  | -		__skb_queue_head_init(&tid->buf_q); | ||||||
|  | +		tid->has_queued  = false; | ||||||
|  |  		__skb_queue_head_init(&tid->retry_q); | ||||||
|  |  		INIT_LIST_HEAD(&tid->list); | ||||||
|  |  		acno = TID_TO_WME_AC(tidno); | ||||||
|  |  		tid->txq = sc->tx.txq_map[acno]; | ||||||
|  | + | ||||||
|  | +		if (!an->sta) | ||||||
|  | +			break; /* just one multicast ath_atx_tid */ | ||||||
|  |  	} | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | @@ -2895,9 +2836,8 @@ void ath_tx_node_cleanup(struct ath_soft | ||||||
|  |  	struct ath_txq *txq; | ||||||
|  |  	int tidno; | ||||||
|  |   | ||||||
|  | -	for (tidno = 0, tid = &an->tid[tidno]; | ||||||
|  | -	     tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { | ||||||
|  | - | ||||||
|  | +	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { | ||||||
|  | +		tid = ATH_AN_2_TID(an, tidno); | ||||||
|  |  		txq = tid->txq; | ||||||
|  |   | ||||||
|  |  		ath_txq_lock(sc, txq); | ||||||
|  | @@ -2909,6 +2849,9 @@ void ath_tx_node_cleanup(struct ath_soft | ||||||
|  |  		tid->active = false; | ||||||
|  |   | ||||||
|  |  		ath_txq_unlock(sc, txq); | ||||||
|  | + | ||||||
|  | +		if (!an->sta) | ||||||
|  | +			break; /* just one multicast ath_atx_tid */ | ||||||
|  |  	} | ||||||
|  |  } | ||||||
|  |   | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| --- a/drivers/net/wireless/ath/ath9k/init.c | --- a/drivers/net/wireless/ath/ath9k/init.c | ||||||
| +++ b/drivers/net/wireless/ath/ath9k/init.c | +++ b/drivers/net/wireless/ath/ath9k/init.c | ||||||
| @@ -728,6 +728,7 @@ static const struct ieee80211_iface_limi | @@ -727,6 +727,7 @@ static const struct ieee80211_iface_limi | ||||||
|  				 BIT(NL80211_IFTYPE_AP) }, |  				 BIT(NL80211_IFTYPE_AP) }, | ||||||
|  	{ .max = 1,	.types = BIT(NL80211_IFTYPE_P2P_CLIENT) | |  	{ .max = 1,	.types = BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||||||
|  				 BIT(NL80211_IFTYPE_P2P_GO) }, |  				 BIT(NL80211_IFTYPE_P2P_GO) }, | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| --- a/drivers/net/wireless/ath/ath9k/debug.c | --- a/drivers/net/wireless/ath/ath9k/debug.c | ||||||
| +++ b/drivers/net/wireless/ath/ath9k/debug.c | +++ b/drivers/net/wireless/ath/ath9k/debug.c | ||||||
| @@ -1319,6 +1319,53 @@ void ath9k_deinit_debug(struct ath_softc | @@ -1315,6 +1315,53 @@ void ath9k_deinit_debug(struct ath_softc | ||||||
|  	ath9k_cmn_spectral_deinit_debug(&sc->spec_priv); |  	ath9k_cmn_spectral_deinit_debug(&sc->spec_priv); | ||||||
|  } |  } | ||||||
|   |   | ||||||
| @@ -54,7 +54,7 @@ | |||||||
|  int ath9k_init_debug(struct ath_hw *ah) |  int ath9k_init_debug(struct ath_hw *ah) | ||||||
|  { |  { | ||||||
|  	struct ath_common *common = ath9k_hw_common(ah); |  	struct ath_common *common = ath9k_hw_common(ah); | ||||||
| @@ -1338,6 +1385,8 @@ int ath9k_init_debug(struct ath_hw *ah) | @@ -1334,6 +1381,8 @@ int ath9k_init_debug(struct ath_hw *ah) | ||||||
|  	ath9k_tx99_init_debug(sc); |  	ath9k_tx99_init_debug(sc); | ||||||
|  	ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy); |  	ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy); | ||||||
|   |   | ||||||
|   | |||||||
| @@ -8,4 +8,4 @@ | |||||||
| +#define ATH_RXBUF               256 | +#define ATH_RXBUF               256 | ||||||
|  #define ATH_TXBUF               512 |  #define ATH_TXBUF               512 | ||||||
|  #define ATH_TXBUF_RESERVE       5 |  #define ATH_TXBUF_RESERVE       5 | ||||||
|  #define ATH_MAX_QDEPTH          (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE) |  #define ATH_TXMAXTRY            13 | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| --- a/drivers/net/wireless/ath/ath9k/debug.c | --- a/drivers/net/wireless/ath/ath9k/debug.c | ||||||
| +++ b/drivers/net/wireless/ath/ath9k/debug.c | +++ b/drivers/net/wireless/ath/ath9k/debug.c | ||||||
| @@ -1366,6 +1366,52 @@ static const struct file_operations fops | @@ -1362,6 +1362,52 @@ static const struct file_operations fops | ||||||
|  	.owner = THIS_MODULE |  	.owner = THIS_MODULE | ||||||
|  }; |  }; | ||||||
|   |   | ||||||
| @@ -53,7 +53,7 @@ | |||||||
|  int ath9k_init_debug(struct ath_hw *ah) |  int ath9k_init_debug(struct ath_hw *ah) | ||||||
|  { |  { | ||||||
|  	struct ath_common *common = ath9k_hw_common(ah); |  	struct ath_common *common = ath9k_hw_common(ah); | ||||||
| @@ -1387,6 +1433,8 @@ int ath9k_init_debug(struct ath_hw *ah) | @@ -1383,6 +1429,8 @@ int ath9k_init_debug(struct ath_hw *ah) | ||||||
|   |   | ||||||
|  	debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, |  	debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, | ||||||
|  			    &fops_eeprom); |  			    &fops_eeprom); | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| --- a/drivers/net/wireless/ath/ath9k/ath9k.h | --- a/drivers/net/wireless/ath/ath9k/ath9k.h | ||||||
| +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | ||||||
| @@ -816,6 +816,9 @@ static inline int ath9k_dump_btcoex(stru | @@ -814,6 +814,9 @@ static inline int ath9k_dump_btcoex(stru | ||||||
|  #ifdef CPTCFG_MAC80211_LEDS |  #ifdef CPTCFG_MAC80211_LEDS | ||||||
|  void ath_init_leds(struct ath_softc *sc); |  void ath_init_leds(struct ath_softc *sc); | ||||||
|  void ath_deinit_leds(struct ath_softc *sc); |  void ath_deinit_leds(struct ath_softc *sc); | ||||||
| @@ -10,7 +10,7 @@ | |||||||
|  #else |  #else | ||||||
|  static inline void ath_init_leds(struct ath_softc *sc) |  static inline void ath_init_leds(struct ath_softc *sc) | ||||||
|  { |  { | ||||||
| @@ -952,6 +955,13 @@ void ath_ant_comb_scan(struct ath_softc | @@ -950,6 +953,13 @@ void ath_ant_comb_scan(struct ath_softc | ||||||
|   |   | ||||||
|  #define ATH9K_NUM_CHANCTX  2 /* supports 2 operating channels */ |  #define ATH9K_NUM_CHANCTX  2 /* supports 2 operating channels */ | ||||||
|   |   | ||||||
| @@ -24,7 +24,7 @@ | |||||||
|  struct ath_softc { |  struct ath_softc { | ||||||
|  	struct ieee80211_hw *hw; |  	struct ieee80211_hw *hw; | ||||||
|  	struct device *dev; |  	struct device *dev; | ||||||
| @@ -1004,9 +1014,8 @@ struct ath_softc { | @@ -1002,9 +1012,8 @@ struct ath_softc { | ||||||
|  	spinlock_t chan_lock; |  	spinlock_t chan_lock; | ||||||
|   |   | ||||||
|  #ifdef CPTCFG_MAC80211_LEDS |  #ifdef CPTCFG_MAC80211_LEDS | ||||||
| @@ -201,7 +201,7 @@ | |||||||
|  #endif |  #endif | ||||||
| --- a/drivers/net/wireless/ath/ath9k/debug.c | --- a/drivers/net/wireless/ath/ath9k/debug.c | ||||||
| +++ b/drivers/net/wireless/ath/ath9k/debug.c | +++ b/drivers/net/wireless/ath/ath9k/debug.c | ||||||
| @@ -1411,6 +1411,61 @@ static const struct file_operations fops | @@ -1407,6 +1407,61 @@ static const struct file_operations fops | ||||||
|  	.llseek = default_llseek, |  	.llseek = default_llseek, | ||||||
|  }; |  }; | ||||||
|   |   | ||||||
| @@ -263,7 +263,7 @@ | |||||||
|   |   | ||||||
|  int ath9k_init_debug(struct ath_hw *ah) |  int ath9k_init_debug(struct ath_hw *ah) | ||||||
|  { |  { | ||||||
| @@ -1435,6 +1490,10 @@ int ath9k_init_debug(struct ath_hw *ah) | @@ -1431,6 +1486,10 @@ int ath9k_init_debug(struct ath_hw *ah) | ||||||
|  			    &fops_eeprom); |  			    &fops_eeprom); | ||||||
|  	debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, |  	debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | ||||||
|  			    sc, &fops_chanbw); |  			    sc, &fops_chanbw); | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
|  	int (*external_reset)(void); |  	int (*external_reset)(void); | ||||||
| --- a/drivers/net/wireless/ath/ath9k/init.c | --- a/drivers/net/wireless/ath/ath9k/init.c | ||||||
| +++ b/drivers/net/wireless/ath/ath9k/init.c | +++ b/drivers/net/wireless/ath/ath9k/init.c | ||||||
| @@ -581,6 +581,7 @@ static int ath9k_init_softc(u16 devid, s | @@ -580,6 +580,7 @@ static int ath9k_init_softc(u16 devid, s | ||||||
|  		ah->external_reset = pdata->external_reset; |  		ah->external_reset = pdata->external_reset; | ||||||
|  		ah->disable_2ghz = pdata->disable_2ghz; |  		ah->disable_2ghz = pdata->disable_2ghz; | ||||||
|  		ah->disable_5ghz = pdata->disable_5ghz; |  		ah->disable_5ghz = pdata->disable_5ghz; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| --- a/drivers/net/wireless/ath/ath9k/debug.c | --- a/drivers/net/wireless/ath/ath9k/debug.c | ||||||
| +++ b/drivers/net/wireless/ath/ath9k/debug.c | +++ b/drivers/net/wireless/ath/ath9k/debug.c | ||||||
| @@ -1467,6 +1467,50 @@ static const struct file_operations fops | @@ -1463,6 +1463,50 @@ static const struct file_operations fops | ||||||
|  #endif |  #endif | ||||||
|   |   | ||||||
|   |   | ||||||
| @@ -51,7 +51,7 @@ | |||||||
|  int ath9k_init_debug(struct ath_hw *ah) |  int ath9k_init_debug(struct ath_hw *ah) | ||||||
|  { |  { | ||||||
|  	struct ath_common *common = ath9k_hw_common(ah); |  	struct ath_common *common = ath9k_hw_common(ah); | ||||||
| @@ -1494,6 +1538,8 @@ int ath9k_init_debug(struct ath_hw *ah) | @@ -1490,6 +1534,8 @@ int ath9k_init_debug(struct ath_hw *ah) | ||||||
|  	debugfs_create_file("gpio_led", S_IWUSR, |  	debugfs_create_file("gpio_led", S_IWUSR, | ||||||
|  			   sc->debug.debugfs_phy, sc, &fops_gpio_led); |  			   sc->debug.debugfs_phy, sc, &fops_gpio_led); | ||||||
|  #endif |  #endif | ||||||
|   | |||||||
| @@ -55,7 +55,7 @@ | |||||||
|  	ops->spectral_scan_config = ar9003_hw_spectral_scan_config; |  	ops->spectral_scan_config = ar9003_hw_spectral_scan_config; | ||||||
| --- a/drivers/net/wireless/ath/ath9k/init.c | --- a/drivers/net/wireless/ath/ath9k/init.c | ||||||
| +++ b/drivers/net/wireless/ath/ath9k/init.c | +++ b/drivers/net/wireless/ath/ath9k/init.c | ||||||
| @@ -717,7 +717,8 @@ static void ath9k_init_txpower_limits(st | @@ -716,7 +716,8 @@ static void ath9k_init_txpower_limits(st | ||||||
|  	if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) |  	if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) | ||||||
|  		ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ); |  		ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ); | ||||||
|   |   | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> | |||||||
|   |   | ||||||
|  #include "common.h" |  #include "common.h" | ||||||
|  #include "debug.h" |  #include "debug.h" | ||||||
| @@ -962,6 +963,14 @@ struct ath_led { | @@ -960,6 +961,14 @@ struct ath_led { | ||||||
|  	struct led_classdev cdev; |  	struct led_classdev cdev; | ||||||
|  }; |  }; | ||||||
|   |   | ||||||
| @@ -33,7 +33,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> | |||||||
|  struct ath_softc { |  struct ath_softc { | ||||||
|  	struct ieee80211_hw *hw; |  	struct ieee80211_hw *hw; | ||||||
|  	struct device *dev; |  	struct device *dev; | ||||||
| @@ -1016,6 +1025,9 @@ struct ath_softc { | @@ -1014,6 +1023,9 @@ struct ath_softc { | ||||||
|  #ifdef CPTCFG_MAC80211_LEDS |  #ifdef CPTCFG_MAC80211_LEDS | ||||||
|  	const char *led_default_trigger; |  	const char *led_default_trigger; | ||||||
|  	struct list_head leds; |  	struct list_head leds; | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> | |||||||
| --- | --- | ||||||
| --- a/drivers/net/wireless/ath/ath9k/ath9k.h | --- a/drivers/net/wireless/ath/ath9k/ath9k.h | ||||||
| +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | ||||||
| @@ -1027,6 +1027,7 @@ struct ath_softc { | @@ -1025,6 +1025,7 @@ struct ath_softc { | ||||||
|  	struct list_head leds; |  	struct list_head leds; | ||||||
|  #ifdef CONFIG_GPIOLIB |  #ifdef CONFIG_GPIOLIB | ||||||
|  	struct ath9k_gpio_chip *gpiochip; |  	struct ath9k_gpio_chip *gpiochip; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Felix Fietkau
					Felix Fietkau