From: Felix Fietkau <nbd@openwrt.org>
To: Johannes Berg <johannes@sipsolutions.net>
Cc: linux-wireless@vger.kernel.org
Subject: Re: [PATCH v3] mac80211: add an intermediate software queue implementation
Date: Tue, 17 Mar 2015 13:04:33 +0100 [thread overview]
Message-ID: <55081851.4030105@openwrt.org> (raw)
In-Reply-To: <1426591453.1985.40.camel@sipsolutions.net>
On 2015-03-17 12:24, Johannes Berg wrote:
> On Tue, 2015-03-17 at 11:21 +0100, Felix Fietkau wrote:
>> @@ -1257,6 +1284,8 @@ struct ieee80211_vif {
>> u8 cab_queue;
>> u8 hw_queue[IEEE80211_NUM_ACS];
>>
>> + struct ieee80211_txq *txq;
>
> This is just one txq, the mcast one? Perhaps that should be cab_txq
> then?
That would be misleading, since this queue is only used when CAB isn't
(i.e. no sta in PS).
> Or is it multiple, then perhaps it should be "txqs"?
>
>> + struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
>
> I wonder if there's a way to make this a single pointer here only? But I
> guess with variable-sized driver data this would be really difficult.
Maybe a potential optimization for later - I'd like to keep it simple
for now...
>> @@ -1818,6 +1872,9 @@ enum ieee80211_hw_flags {
>> * @n_cipher_schemes: a size of an array of cipher schemes definitions.
>> * @cipher_schemes: a pointer to an array of cipher scheme definitions
>> * supported by HW.
>> + *
>> + * @txq_ac_max_pending: maximum number of frames per AC pending in all txq
>> + * entries for a vif.
>
> I think you should give some guidance on how to best set this value,
> like max aggregation size or something? I'm not really sure :)
I don't have any guidance for tuning this in the driver just yet.
For devices with software aggregation, it should just be left at the
default value.
>> + if (sta_prepare_rate_control(local, sta, gfp))
>> + goto free_txq;
>
> Does it even have to come before rate control?
It doesn't have to, but I figured cleanup is simpler that way.
>> @@ -1090,10 +1119,25 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
>>
>> BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
>> sta->driver_buffered_tids = 0;
>> + sta->txq_buffered_tids = 0;
>>
>> if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
>> drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
>>
>> + if (sta->txqi) {
>> + for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
>> + struct txq_info *txqi;
>> +
>> + txqi = container_of(sta->sta.txq[i], struct txq_info,
>> + txq);
>> +
>> + if (!skb_queue_len(&txqi->queue))
>> + continue;
>> +
>> + drv_wake_tx_queue(local, txqi);
>> + }
>> + }
>
> This could be an interesting race. If you wake the queue, and then the
> station goes to sleep again before the driver had a chance to pull
> frames, what happens? Should the driver be responsible for this? But you
> don't have "unwake_tx_queue", so maybe you should not return any frame
> from the dequeue in such a case?
The driver is responsible for making sure that any queue of a sleeping
sta is not scheduled.
>> @@ -1447,6 +1493,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
>>
>> sta_info_recalc_tim(sta);
>> } else {
>> + unsigned long tids = sta->txq_buffered_tids & driver_release_tids;
>
> I'm not sure I understand this. Are you treating txq_buffered_tids as
> driver-buffered?
Yes. As explained in the DOC section, PS delivery of txq buffered frames
goes through drv_release_buffered_frames. Maybe I could change the
wording a bit to make it more clear.
>> @@ -368,6 +369,8 @@ struct sta_info {
>> struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
>> struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
>> unsigned long driver_buffered_tids;
>> + unsigned long txq_buffered_tids;
>> + struct txq_info *txqi;
>
> Hm, so, internally you allocate one big thing and externally to the
> driver you have a per-TID array.
>
> Why not just remove this pointer, and keep only the per-TID array? You'd
> have to do a bit more container_of() but I don't think that's a big
> deal? Plus you can't really use this anyway since you can't index it,
> i.e. you cannot say sta->txqi[t] since the size doesn't match up.
Will do
>> +static void ieee80211_drv_tx(struct ieee80211_local *local,
>> + struct ieee80211_vif *vif,
>> + struct ieee80211_sta *pubsta,
>> + struct sk_buff *skb)
>> +{
>> + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
>> + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
>> + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
>> + struct ieee80211_tx_control control = {
>> + .sta = pubsta
>> + };
>> + struct ieee80211_txq *txq = NULL;
>> + struct txq_info *txqi;
>> + u8 ac;
>> +
>> + if (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)
>> + goto tx_normal;
>> +
>> + if (ieee80211_is_mgmt(hdr->frame_control) ||
>> + ieee80211_is_ctl(hdr->frame_control))
>> + goto tx_normal;
>
> Doesn't this become awkward with powersave handling for bufferable mgmt
> frames? They'd be stored on the per-station non-txq queues, but then the
> wakeup handling needs to see which ones to take first? Having these on
> the txqs might make that part easier?
I guess I'll change it to throw bufferable mgmt frames in the txq as well.
> OTOH, I guess it would make building A-MPDUs or even A-MSDUs far more
> complicated, so I guess it's a reasonable tradeoff.
>
>> +struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
>> + struct ieee80211_txq *txq)
>> +{
>> + struct ieee80211_local *local = hw_to_local(hw);
>> + struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
>> + struct txq_info *txqi = container_of(txq, struct txq_info, txq);
>> + struct sk_buff *skb;
>> + u8 ac = txq->ac;
>> +
>> + skb = skb_dequeue(&txqi->queue);
>> + if (!skb)
>> + return ERR_PTR(-EAGAIN);
>
> why not just return NULL?
I guess initially I wanted to be able to return other error codes as
well, but now I'm not sure I need that anymore. I'll change it to NULL.
>> + atomic_dec(&sdata->txqs_len[ac]);
>> + if (__netif_subqueue_stopped(sdata->dev, ac))
>> + ieee80211_propagate_queue_wake(local, sdata->vif.hw_queue[ac]);
>
> Do you really want to do that unconditionally? There could be a lot of
> frames on the queue still, or even on other station queues?
Unconditionally? ieee80211_propagate_queue_wake checks the per-sdata txq
limit.
>> + if (sta) {
>> + txqi->txq.sta = &sta->sta;
>> + sta->sta.txq[tid] = &txqi->txq;
>> + txqi->txq.ac = ieee802_1d_to_ac[tid & 7];
>
> I think you should probably restrict this to 8 TIDs anyway... nobody
> uses 16 TIDs, and the mapping for the higher 8 TIDs is dynamic so this
> is always wrong. Using just 8 instead of 16 will also save a lot of
> memory I guess.
>
> If you want TSPECs, then you probably want the WMM ones, which also only
> use the lower 8 TIDs. Only if you really wanted the 802.11 QoS TSPEC you
> might need the higher 8 TIDs ...
Right, limiting it to 8 makes sense.
> Anyway - overall I think this looks pretty good. What we discussed in
> Ottawa was that we should perhaps forego the whole qdisc and netdev
> queue start/stop and just do something like the qdisc would do in the
> layer of these queues, although then we'd have to first convert every
> driver or make this layer mandatory in some other way. That's something
> we should explore here I think.
I agree. Figuring out what tx queue scheduling should look like for
devices with firmware based aggregation is going to be interesting
though...
- Felix
next prev parent reply other threads:[~2015-03-17 12:04 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-03-17 10:21 [PATCH v3] mac80211: add an intermediate software queue implementation Felix Fietkau
2015-03-17 11:24 ` Johannes Berg
2015-03-17 12:04 ` Felix Fietkau [this message]
2015-03-17 12:52 ` Johannes Berg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=55081851.4030105@openwrt.org \
--to=nbd@openwrt.org \
--cc=johannes@sipsolutions.net \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.