Atheros HAL API
The Atheros HAL API is, as its name suggests, a "hardware abstraction layer" designed to hide the hardware specific building blocks from the ath(4) driver. It also provides a set of methods to extract statistics, configure optional behaviours of the hardware and get a list of hardware capabilities.
There is also support for pluggable RF modules for the various external radios supported by the Atheros chipset family. Starting with the AR9280 the radios are built-in rather than external but the framework lives on.
The HAL is broken up into a few areas:
- Regulatory information
- EEPROM decoding
- RF programming
- Everything else
There are a few design choices in the HAL code that are worth noting.
The HAL code is / was designed to be platform independent - ie, it should compile and be useful on a variety of differing operating systems and architectures. Although right now this HAL primarily targets *BSD (and FreeBSD in particular), a design aim is to keep this as a reference to be useful by other operating system projects (eg OpenSolaris, Haiku, ReactOS, etc.)
The HAL code supports multiple operating modes - ie, there is supposed to be one HAL for both station and access-point operation. In the past there was an AP-centric and STA-centric HAL.
The HAL layer assumes the driver layer is responsible for all locking and concurrency. There are no locks and no atomic operations in the HAL. Any kind of locking that is needed must be done by the driver.
API structures / types / enums
The API is documented in ath_hal/ah.h . The debugging information is in ath_hal/ah_debug.h. The diagnostic API codes are in ath_hal/ah_diagcodes.h .
Probe / Attach
The HAL exposes two methods to do hardware probe and attach. These aren't registered with the main HAL structure; they instead are generally located in the xxxx_attach.c function in the chip directory; using the AH_CHIP() macro.
Similarly, the RF backends are registered through a call to the AH_RF() macro.
Allocating the HAL state
The "ath_hal" struct in ath_hal/ah.h contains the basic public facing state and method function pointers that are setup during device attach.
The "ath_hal_private" struct in ath_hal/ah_private.h contains the HAL-facing state which isn't directly exposed to the rest of the ath(4) driver layer. The first entry in ath_hal_private is an ath_hal struct.
Each HAL chipset will define its structure by declaring an ath_hal_private struct at the beginning.
The attach routine will then allocate a chipset specific struct (eg ath_hal_5212) from the operating system and fill that out. Because of the above, this allocation will include both ath_hal and ath_hal_private.
With this in mind, the order of the HAL state structure will look like this in memory:
- (chipset-specific HAL state)
Various macros are then used to get to the right state:
- AH_PRIVATE(ah) returns a pointer to the start of the private state;
- AHchip(ah) (eg AH5212(ah) ) will return a pointer to the start of the chip state.
HAL: Reset functions
The reset functions control chipset reset (eg to clear a hardware stuck condition, or to change channel), do calibration, set TX power limits and disable/enable parts of the chipset (such as the PHY, or the PCIe host bus.)
HAL: Transmit functions
The transmit functions handle a variety of transmit related operations:
- Setting up the hardware TX queues and mapping between DCU and QCU;
- Starting and stopping TX DMA;
- Fetching the state of the TX DMA engine and hardware TX queues;
- Preparing TX descriptors with the relevant information to transmit a frame;
- Fetching the TX descriptor completion status in order to see whether a frame has transmitted or not and if so, what happened;
- Configure and fetch the state of the TX queues after an interrupt.
HAL: Receive functions
The receive functions handle a variety of receive related operations:
- Setting up the hardware RX queue(s);
- Enabling and disabling RX DMA;
- Configuring the RX DMA queue or FIFO in order to receive frames;
- Fetch the RX descriptor completion status to get information about completing frames;
- Program the multicast RX filter;
- Program the hardware RX filter (for things such as promiscuous mode);
- Handle the periodic ANI polling and interrupt processing.
HAL: Miscellaneous functions
A lot happens here unfortunately.
- Capability and diagnostic API;
- Configure and fetch MAC address;
- Configure and fetch the BSS ID mask;
- Regulatory domain information;
- Configure LED state;
- Configure and drive the GPIO pin infrastructure;
- Fetch and set the TSF counter(s);
- Configure and fetch the transmit and receive antennas;
- Configure and set the slot time, IFS time, ACK/CTS timeout, ACK/CTS rate, and coverage class;
- Configure QUIET time handling;
- Setup TX and RX chainmasks (for MIMO devices.)
HAL: DFS / Radar Functions
The radar functions configure the radar threshold detection parameters and can also be used to parse the radar frames.
HAL: Keycache management functions
The keycache is where per-MAC and global encryption / decryption keys are stored. These functions handle managing this table in the hardware.
HAL: Power Management functions
The power management functions implement chipset power save. This puts various parts of the MAC/PHY to sleep and can forcibly wake it up.
For now this isn't used outside of attach/detach.
HAL: Beacon functions
The beacon functions configure various aspects to both beacon generation (for AP and IBSS modes) and beacon reception (for STA/IBSS modes.)
When acting as a master device (IBSS/AP), the hardware will generate periodic beacons. These methods configure up the beacon interval timing.
When acting as a slave device (IBSS/STA) the hardware will listen for beacons and synchronise some state with received beacons. This mostly involves synchronising the TSF against the AP/master IBSS node, as well as optionally waking up the device if it's asleep.
HAL: Interrupt functions
The interrupt functions handle configuring the interrupt mask, enabling/disabling interrupts and fetching the current interrupt state.
HAL: EEPROM functions
The EEPROM functions provide hardware level access to the EEPROM space - ie, reading and writing individual words to the EEPROM. For devices which implement multiple types of EEPROM access (eg the AR9380 and later devices), they can override these methods as needed.