Packet Queues

The High MAC Framework provides a flexible packet queueing subsystem. MAC applications can create and manipulate queues as needed.

The High MAC Framework uses queues for the following purposes:

  • The Ethernet portal maintains a queue of received Ethernet frames provided by the platform
  • The Ethernet portal also maintains a queue of to-be-sent Ethernet frames that originated as wireless receptions
  • wlan_exp maintains a queue of received Ethernet frames that are valid wlan_exp commands
  • wlan_exp maintains a queue of to-be-sent Ethernet frames that are wlan_exp responses

The AP, STA, and IBSS applications all use this packet queueing system to maintain wireless Tx queues organized by packet type (management, multicast, data) and destination address. The per-station queues are tracked via the Station Information subsystem

The queue framework code is in wlan_mac_queue.c.

Overview

The High MAC Framework’s packet queueing code relies on three data structures:

  • Queue Buffer: a fixed-size block of RAM which stores a queued packet and its metadata
  • Queue Entry: a doubly-linked list entry which points to a single Queue Buffer
  • Queue: a doubly-linked list of Queue Entries

There is a fixed one-to-one mapping of Queue Entries and Queue Buffers established at boot by the framework. The association between a Queue Entry and its Queue Buffer never changes.

By default the framework stores Queue Buffers in off-chip DRAM (large, high-latency memory) and Queue Entries in on-chip block RAM (small, low-latency memory). This scheme reduces the latency for manipulating queue entries while preserving a large memory area for queued packets.

Queue State

Individual queues are identified by an integer Queue ID. MAC applications create new queues by referencing a new Queue ID. Internally the High MAC Framework maintains an array of queues indexed by Queue ID. MAC applications should use the smallest set of integers starting at zero for their Queue IDs.

Function Description
u32 queue_num_queued(u16 queue_sel) Queries the number of packets in a queue
void purge_queue(u16 queue_sel) Removes all entries from a queue and returns them to the Free Pool

Checkout/Checkin

At boot the framework puts every Queue Entry in a dedicated Free Pool. The Free Pool is a doubly-link list of available Queue Entries maintained by the framework. Queue Buffers for Entries in the Free Pool are considered empty (while not explicitly set to zero, but will be overwritten by the next user of the buffer).

When the MAC application requests a Queue Entry the framework removes one Entry from the Free Pool and returns it to the application. At this point the Queue Entry is not associated with any queue. The application must either fill the associated Queue Buffer then enqueue the entry or return the entry to the free pool.

When the MAC application is finished with a Queue Entry (i.e. when a packet has been submitted to the lower MAC for transmission), the Queue Entry is returned to the framework and added to the Free Pool. The application interacts with the Free Pool via these functions:

Function Description
dl_entry* queue_checkout() Framework gives application a free Queue Entry
void queue_checkin(dl_entry* queue_entry) Application gives Queue Entry back to Framework
void transmit_checkin(dl_entry* queue_entry) Application provides Queue Entry to Framework to transmit then checkin
u32 queue_num_free() Queries the number of Queue Entries in the Free Pool

Enqueue/Dequeue

Once the MAC application has checked out a free Queue Entry and created a packet in the associated Queue Buffer, the entry can be enqueued. Later, when the MAC application is ready to process an enqueued packet it dequeues a packet from a specified queue.

Once a Queue Entry is dequeued the entry is no longer associated with its previous Queue. The MAC application must re-enqueue the entry or return the entry to the Free Pool.

Function Description
void enqueue_after_tail(u16 queue_sel, dl_entry* queue_entry) Adds a Queue Entry to the end of the specified Queue
dl_entry* dequeue_from_head(u16 queue_sel) Removes and returns the first Queue Entry from the specified Queue

Memory Notes

The total number of Queue Entries/Buffers depends on how much DRAM/BRAM is provided in the FPGA design and hardware platform. The TX_QUEUE_DL_ENTRY_MEM_SIZE and TX_QUEUE_BUFFER_SIZE macros define the allocated BRAM and DRAM areas and are used to calculate the total_tx_queue_entries value in wlan_mac_queue_init().

The High MAC Framework makes specific assumptions about how MAC applications handle Queue Entries. Applications must adhere to these rules to avoid leaking memory.

  • Every entry checked out with queue_checkout() will be checked in with queue_checkin() or transmit_checkin().
  • Every enqueued entry will eventually be dequeued then checked in

A Queue Entry is always in one of three states:

  • Free: entry is in the Free Pool and will eventually be used via queue_checkout()
  • Enqueued: the application has added the entry to a queue
  • Floating: an entry that has been checked out but not enqueued

The High MAC Framework queue code only maintains references to Free and Enqueued entries. The application must maintain its own reference to Floating entries. A Queue Entry can be permanently lost if the entry pointer is stored in a local variable before a context switch. Code which checks out an entry (queue_checkout()) must eventually enqueue it or check it in.