STRUCT IWL_TXQ(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

okay bestie, let's talk about struct iwl_txq(9) from the kernel API manual πŸ’–

So like, this is a Tx Queue for DMA, and it's giving main character energy in the wireless driver world. Let me walk you through every single detail so you're not out here looking clueless, okay? 🫢


✨ SYNOPSIS ✨

struct iwl_txq {
    void *tfds;
    struct iwl_pcie_first_tb_buf *first_tb_bufs;
    dma_addr_t first_tb_dma;
    struct iwl_pcie_txq_entry *entries;
    spinlock_t lock;
    spinlock_t reclaim_lock;
    unsigned long frozen_expiry_remainder;
    struct timer_list stuck_timer;
    struct iwl_trans *trans;
    bool need_update;
    bool frozen;
    bool ampdu;
    int block;
    unsigned long wd_timeout;
    struct sk_buff_head overflow_q;
    struct iwl_dma_ptr bc_tbl;
    int write_ptr;
    int read_ptr;
    dma_addr_t dma_addr;
    int n_window;
    u32 id;
    int low_mark;
    int high_mark;
    bool overflow_tx;
 };

🌸 MEMBERS 🌸

okay so every single one of these matters, no skipping, periodt πŸ’…

  • tfds β€” transmit frame descriptors, and yes they live in DMA memory. iconic.
  • first_tb_bufs β€” start of command headers, including scratch buffers, for the writeback. This is DMA memory and an array holding one buffer for each command on the queue. she's fancy like that ✨
  • first_tb_dma β€” the DMA address for the first_tb_bufs start. literally just the address, nbd.
  • entries β€” transmit entries, a.k.a. driver state. you know, the behind-the-scenes stuff πŸŽ€
  • lock β€” queue lock. don't touch without it.
  • reclaim_lock β€” reclaim lock. also important, also don't touch.
  • frozen_expiry_remainder β€” remember how long until the timer fires. it's giving "notes app reminder" energy.
  • stuck_timer β€” timer that fires if queue gets stuck. lowkey the drama detector πŸ’€
  • trans β€” pointer back to transport (for timer). she needs to know where she came from.
  • need_update β€” indicates need to update read/write index. simple as that.
  • frozen β€” tx stuck queue timer is frozen. like paused, not cold.
  • ampdu β€” true if this queue is an ampdu queue for a specific RA/TID. iykyk.
  • block β€” queue is blocked. rude but necessary.
  • wd_timeout β€” queue watchdog timeout (jiffies) β€” per queue. keep an eye on it.
  • overflow_q β€” overflow queue for handling frames that didn't fit on HW queue. the "spill the tea" queue, honestly πŸ“
  • bc_tbl β€” byte count table of the queue (relevant only for gen2 transport). gen2 girlies only.
  • write_ptr β€” 1st empty entry (index) host_w. yes, that's the name.
  • read_ptr β€” last used entry (index) host_r. matching set, cute.
  • dma_addr β€” physical addr for BDs. not virtual, don't get it twisted.
  • n_window β€” safe queue window. the comfy zone 🌈
  • id β€” queue id. everyone has one.
  • low_mark β€” low watermark, resume queue if free space more than this. wake her up when there's room.
  • high_mark β€” high watermark, stop queue if free space less than this. hit the brakes, bestie.
  • overflow_tx β€” need to transmit from overflow. when the overflow queue gets its moment πŸ”₯

πŸ’– DESCRIPTION πŸ’–

So a Tx queue consists of a circular buffer of BDs (a.k.a. TFDs, transmit frame descriptors) and required locking structures. That's the whole vibe.

Now pay attention, because this part is lowkey the most important thing on the page:

Note the difference between TFD_QUEUE_SIZE_MAX and n_window: the hardware always assumes 256 descriptors, so TFD_QUEUE_SIZE_MAX is always 256 (unless there might be HW changes in the future). For the normal TX queues, n_window, which is the size of the software queue data, is also 256; however, for the command queue, n_window is only 32 since we don't need so many commands pending. Since the HW still uses 256 BDs for DMA though, TFD_QUEUE_SIZE_MAX stays 256.

This means that we end up with the following:

HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
SW entries:           | 0      | ... | 31          |

where N is a number between 0 and 7. This means that the SW data is a window overlaid over the HW queue. no cap, that's literally how it works πŸ’€βœ¨


🌈 SEE ALSO 🌈

okay bestie, here's the whole friend group β€” go check them out, they're all part of the same kernel file ./drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h:

  • struct iwl_rx_mem_buffer(9)
  • struct iwl_rx_transfer_desc(9)
  • struct iwl_rx_completion_desc(9)
  • struct iwl_rx_completion_desc_bz(9)
  • struct iwl_rxq(9)
  • struct iwl_rb_allocator(9)
  • iwl_get_closed_rb_stts(9)
  • enum iwl_fw_mon_dbgfs_state(9)
  • enum iwl_shared_irq_flags(9)
  • enum iwl_image_response_code(9)
  • struct cont_rec(9)
  • enum iwl_pcie_imr_status(9)
  • struct iwl_pcie_txqs(9)
  • struct iwl_trans_pcie(9)
  • iwl_txq_inc_wrap(9)
  • iwl_txq_dec_wrap(9)

okay that's the whole page, bestie! this one came from ./drivers/net/wireless/intel/i... and it's dated October 2026, and it's all about struct iwl_txq(9). slay πŸ’…βœ¨πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from