Search Linux Wireless

Re: [RFC PATCH 06/13] wifi: mac80211: Add new TX queues to replace legacy TX

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 2025-01-27 at 17:26 +0100, Alexander Wetzel wrote:
> 
> +++ b/net/mac80211/iface.c
> @@ -1124,11 +1124,63 @@ static void ieee80211_sdata_init(struct ieee80211_local *local,
>  	 * MLD connection, we get a separate allocation for it.
>  	 */
>  	ieee80211_link_init(sdata, -1, &sdata->deflink, &sdata->vif.bss_conf);
> +
> +	for (int i = 0; i < NUM_NL80211_BANDS; i++) {
> +		struct ieee80211_supported_band *sband;
> +
> +		sband = local->hw.wiphy->bands[i];
> +		sdata->rc_rateidx_mask[i] =
> +			sband ? (1 << sband->n_bitrates) - 1 : 0;


Feels like this code move should perhaps be in a separate refactoring
patch?

> +static void ieee80211_vif_txq_init(struct ieee80211_sub_if_data *sdata,
> +				   int txq_offset, int txq_size, int num_queues)
> +{
> +	void *buffer = (char *)sdata + txq_offset;

That seems ... awkward at best, my first instinct would be to say this
must be wrong.

Do we really need to do this dynamically just to save two a bit of
memory for VLAN and (virtual) monitor interfaces?

Would probably be better to use pointers to a TXQ array instead of
embedding them then, or otherwise just embed enough for all kinds of
interfaces and just not use them.

> -void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
> +static void ieee80211_purge_txqs(struct ieee80211_sub_if_data *sdata)
>  {
> -	struct ieee80211_txq *txq = sdata->vif.txq[IEEE80211_VIF_TXQ_MULTICAST];
> +	struct sta_info *sta;
>  
> +	list_for_each_entry(sta, &sdata->local->sta_list, list) {
> +		if (sdata != sta->sdata)
> +			continue;
> +		ieee80211_purge_sta_txqs(sta);
> +	}
> +
> +	for (int i = IEEE80211_VIF_TXQ_MULTICAST;
> +	     i <= IEEE80211_VIF_TXQ_FALLBACK;
> +	     i++) {
> +		if (sdata->vif.txq[i])
> +			ieee80211_txq_purge(sdata->local,
> +					    to_txq_info(sdata->vif.txq[i]));
> +	}
> +
> +	synchronize_rcu();

You should keep the synchronize_rcu() outside this function. It's
expensive, and

> @@ -2300,6 +2342,8 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
>  	list_for_each_entry_safe(sdata, tmp, &unreg_list, list) {
>  		bool netdev = sdata->dev;
>  
> +		ieee80211_purge_txqs(sdata);
> +
>  		/*
>  		 * Remove IP addresses explicitly, since the notifier will
>  		 * skip the callbacks if wdev->registered is false, since

can be amortized across all interfaces in this case.

> @@ -3803,7 +3818,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
>  	struct ieee80211_vif *vif = txq->vif;
>  	int q = vif->hw_queue[txq->ac];
>  	unsigned long flags;
> -	bool q_stopped;
> +	int qsr;

Should be "unsigned long qsr", to match queue_stop_reasons, I guess.

> +		/* Drop off-channel frames if queues are stopped for any reason
> +		 * other than off-channel operation. Never queue them.
> +		 */
> +		if (unlikely(txq->tid == IEEE80211_TXQ_NOQUEUE)) {
> +			WARN(1, "mac80211: Drop noqueue TX. qsr=%i\n", qsr);
> +			ieee80211_txq_purge(local, txqi);
> +			return NULL;
> +		}

if (WARN_ON(...)) { ... }

Perhaps better just "if (WARN_ON_ONCE())", since it's in TX.

> +static void __ieee80211_wake_txq(struct ieee80211_local *local,
> +				 struct ieee80211_txq *txq)
> +{
> +	struct txq_info *txqi = to_txq_info(txq);
> +	struct fq *fq = &local->fq;
> +
> +	if (WARN_ON(!txq))
> +		return;
> +	if (test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags)) {
> +		spin_unlock(&fq->lock);
> +		drv_wake_tx_queue(local, txqi);
> +		spin_lock(&fq->lock);
> +	}
> +}

I really don't like dropping locks in the middle - if that's *really*
needed there better be a very good reason and a good comment indicating
why it's safe, including a comment in the caller that says this happens.

> +	/* %IEEE80211_VIF_TXQ_NOQUEUE must be ignored here */

No need for % outside kernel-doc.

> +
> +	if (ac == IEEE80211_AC_VO) {
> +		__ieee80211_wake_txq(local,
> +				     vif->txq[IEEE80211_VIF_TXQ_FALLBACK]);
> +	}

nit: no need for braces

Why is VO special, not sure I understand the logic of checking the AC?

> +	if (ac == IEEE80211_AC_BE && vif->txq[IEEE80211_VIF_TXQ_MULTICAST] &&
> +	    (!ps || !atomic_read(&ps->num_sta_ps)))
> +		__ieee80211_wake_txq(local,
> +				     vif->txq[IEEE80211_VIF_TXQ_MULTICAST]);

Also here, why BE?

>  	list_for_each_entry_rcu(sta, &local->sta_list, list) {
>  		if (sdata != sta->sdata)
>  			continue;
>  
> -		for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
> +		/* IEEE80211_TXQ_NOQUEUE must be ignored here. */

some of these comments should probably say _why_ too

johannes





[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux