HW QUEUE CONTROL(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

✨ HW queue control ✨

straight outta the Kernel API Manual, section 9 β€” pull up a chair bestie


πŸŽ€ The lore (aka why this exists)

Okay so before HW queue control showed up, mac80211 only had a single static assignment of per-interface AC software queues to hardware queues. And like… it was not it. Problematic for a few reasons, fr:

  1. off-channel transmissions might get stuck behind other frames 😭
  2. multiple virtual interfaces couldn't be handled correctly πŸ’€
  3. after-DTIM frames could get stuck behind other frames πŸ™ˆ

To solve this, hardware typically uses multiple different queues for all the different usages, and this needs to be propagated into mac80211 so it won't have the same problem with the software queues. slay, honestly

πŸ¦‹ How the driver does its thing

Therefore, mac80211 now offers the IEEE80211_HW_QUEUE_CONTROL capability flag that tells it that the driver implements its own queue control. To do so, the driver will set up the various queues in each struct ieee80211_vif and the offchannel queue in struct ieee80211_hw. In response, mac80211 will use those queue IDs in the hw_queue field of struct ieee80211_tx_info and if necessary will queue the frame on the right software queue that mirrors the hardware queue. Additionally, the driver has to then use these HW queue IDs for the queue management functions (ieee80211_stop_queue et al.) iykyk

πŸ’… Setting up the mappings

The driver is free to set up the queue mappings as needed; multiple virtual interfaces may map to the same hardware queues if needed. The setup has to happen during add_interface or change_interface callbacks. no cap, that's the rule

For example, a driver supporting station+station and station+AP modes might decide to have 10 hardware queues to handle different scenarios:

  • 4 AC HW queues for 1st vif: 0, 1, 2, 3
  • 4 AC HW queues for 2nd vif: 4, 5, 6, 7
  • after-DTIM queue for AP: 8
  • off-channel queue: 9

It would then set up the hardware like this:

hw.offchannel_tx_hw_queue = 9

and the first virtual interface that is added as follows:

vif.hw_queue[IEEE80211_AC_VO] = 0
vif.hw_queue[IEEE80211_AC_VI] = 1
vif.hw_queue[IEEE80211_AC_BE] = 2
vif.hw_queue[IEEE80211_AC_BK] = 3
vif.cab_queue = 8 // if AP mode, otherwise IEEE80211_INVAL_HW_QUEUE

and the second virtual interface with 4-7.

🌸 What that actually gets you

If queue 6 gets full, for example, mac80211 would only stop the second virtual interface's BE queue since virtual interface queues are per AC. main character energy: one queue stops, the whole vif doesn't have to suffer

⚠️ Okay this part MATTERS, don't skip it: note that the vif.cab_queue value should be set to IEEE80211_INVAL_HW_QUEUE whenever the queue is not used (i.e. the interface is not in AP mode) if the queue could potentially be shared since mac80211 will look at cab_queue when a queue is stopped/woken even if the interface is not in AP mode. Like, literally set it. Respect the sentinel. 🫢

πŸ’« SEE ALSO πŸ’«

bestie you made it to the end!! πŸŽ‰ here's the whole squad of related pages β€” every single one, no skips, no cap. go click around and get your life πŸ’…βœ¨


that's literally the whole page, bestie 🫢 source: ./include/net, version/date: October 2026, title: HW queue control(9) β€” love u, bye!! πŸ’–πŸŒΈ

πŸ“¦ where this page comes from