This page describes how to initiate DMA from and to the wireless core.
Contents
General
The chip has 6 DMA controllers, each of which has a transmit and a receive channel. Each DMA controller is controlled via its own set of registers, located in the MMIO. Depending on your board, there are two different DMA register layouts. If the 64 bit DMA flag is set in sbtmstatehigh, then use the 64 bit DMA layout, otherwise, use the 32 bit DMA layout.
32 Bit DMA
The 6 DMA controllers are addressed by accessing MMIO offsets 0x200, 0x220, 0x240, 0x260, 0x280 and 0x2A0 respectively.
Controller Registers
Each controller has the following registers, given as offsets of the MMIO addresses:
Offset |
Description |
Transmit Channel |
|
0x00 (4 bytes) |
Control word |
0x04 (4 bytes) |
Descriptor Ring Address |
0x08 (4 bytes) |
Descriptor Stop Index |
0x0C (4 bytes) |
Transmit Status Word |
Receive Channel |
|
0x10 (4 bytes) |
Control word |
0x14 (4 bytes) |
Descriptor Ring Address |
0x18 (4 bytes) |
Descriptor Index |
0x1C (4 bytes) |
Receive Status Word |
All descriptor rings must be 4K aligned and fit into a single 4K page.
Transmit Channel Control Word
The transmit channel control word consists of the following:
Mask |
Function |
0x00000001 |
Enable |
0x00000002 |
Suspend Request |
0x00000004 |
Loopback Enable |
0x00000010 |
Flush Request |
0x00030000 |
Address Extension |
Transmit Channel Status Word
The transmit channel status word consists of the following:
Mask |
Function |
0x00000FFF |
Current Descriptor Pointer |
0x0000F000 |
Transmit State |
0x000F0000 |
Transmit Errors |
0xFFF00000 |
Active Descriptor |
Transmit Errors
This field can take the following values:
Value |
Meaning |
0 |
No Error |
1 |
Descriptor Protocol Error (Indicates the Descriptor Ring Address could not be accessed) |
2 |
Data FIFO Underrun |
3 |
Bus Error on Buffer Read |
4 |
Bus Error on Descriptor Access |
Transmit State
This field can take the following values:
Value |
Meaning |
0 |
Disabled |
1 |
Active |
2 |
Idle Wait |
3 |
Stopped |
4 |
Suspend Pending |
Receive Channel Control Word
The receive channel control word consists of the following:
Mask |
Function |
0x00000001 |
Enable |
0x000000FE |
Frame Offset |
0x00000100 |
Direct FIFO Receive Mode (PIO) |
0x00030000 |
Address Extension Bits |
Receive Channel Status Word
The receive channel status word consists of the following:
Mask |
Function |
0x00000FFF |
Current Descriptor Pointer |
0x0000F000 |
Receive State |
0x000F0000 |
Receive Errors |
0xFFF00000 |
Active Descriptor |
Receive Errors
This field can take the following values:
Value |
Meaning |
0 |
No Error |
1 |
Descriptor Protocol Error (Indicates the Descriptor Ring Address could not be accessed) |
2 |
Data FIFO Overflow |
3 |
Bus Error on Buffer Write |
4 |
Bus Error on Descriptor Access |
Receive State
This field can take the following values:
Value |
Meaning |
0 |
Disabled |
1 |
Active |
2 |
Idle Wait |
3 |
Stopped |
Descriptors
Each descriptor (that is stored into the descriptor ring and posted) contains of two 4 byte fields:
32 Bit DMA Descriptor |
Control |
Address |
(in this order). The descriptor is never modified by the hardware, only read by it.
The control field breaks down as such
Mask |
Function |
0x00001FFF |
Buffer Byte Count |
0x00030000 |
Address Extension Bits |
0x10000000 |
End of Descriptor Table |
0x20000000 |
Interrupt on Completetion Requested |
0x40000000 |
End of Frame |
0x80000000 |
Start of Frame |
The meaning of the flags at the high 4 bits of the control field is clear when you consider scatter-gather-I/O. Each transfer can be posted into or read from multiple buffers. The start of frame flag indicates that this transfer starts a new I/O packet, end of frame indicates that this is the last buffer for one packet.
The interrupt on completion flag signals (if turned on) that an interrupt is requested when this single transfer (not packet) is completed, end of descriptor table is used to signal to the chip that no valid descriptors follow in the memory after this one but that the controller should rather start reading at the beginning of the descriptor ring again.
The address field is as follows:
Mask |
Function |
0x3FFFFFFF |
Address |
0xC0000000 |
Routing |
Known values for the routing value are as follows:
Value |
Function |
0 |
No translation |
1 |
Client Mode Translation (1GB) |
If you have enabled any routing bits, make sure to also set the address extension bits in the control field when setting the address. This allows use of the full 32 bits of address space.
64 Bit DMA
The 6 DMA controllers are addressed by accessing MMIO offsets 0x200, 0x240, 0x280, 0x2C0, 0x300 and 0x340 respectively.
Controller Registers
Each controller has the following registers, given as offsets of the MMIO addresses:
Offset |
Description |
Transmit Channel |
|
0x00 (4 bytes) |
Control Word |
0x04 (4 bytes) |
Descriptor Stop Index |
0x08 (4 bytes) |
Descriptor Ring Address (Low 32 Bits) |
0x0C (4 bytes) |
Descriptor Ring Address (High 32 Bits) |
0x10 (4 bytes) |
Status - State |
0x14 (4 bytes) |
Status - Error |
Receive Channel |
|
0x20 (4 bytes) |
Control Word |
0x24 (4 bytes) |
Descriptor Stop Index |
0x28 (4 bytes) |
Descriptor Ring Address (Low 32 Bits) |
0x2C (4 bytes) |
Descriptor Ring Address (High 32 Bits) |
0x30 (4 bytes) |
Status - State |
0x34 (4 bytes) |
Status - Error |
All descriptor rings must be 8K aligned and fit into a single 8K page.
Transmit Channel Control Word
The transmit channel control word consists of the following:
Mask |
Function |
0x00000001 |
Enable |
0x00000002 |
Suspend Request |
0x00000004 |
Loopback Enable |
0x00000010 |
Flush Request |
0x00030000 |
Address Extension |
Transmit Channel Status - State
The transmit channel status state word consists of the following:
Mask |
Function |
0x00001FFF |
Current Descriptor Pointer |
0xF0000000 |
Transmit State |
Transmit State
This field can take the following values:
Value |
Meaning |
0 |
Disabled |
1 |
Active |
2 |
Idle Wait |
3 |
Stopped |
4 |
Suspend Pending |
Transmit Channel Status - Errors
The transmit channel status errors word consists of the following:
Mask |
Function |
0x0001FFFF |
Active Descriptor Pointer |
0xF0000000 |
Transmit Errors |
Transmit Errors
This field can take the following values:
Value |
Meaning |
0 |
No Error |
1 |
Descriptor Protocol Error (Indicates the Descriptor Ring Address could not be accessed) |
2 |
Data FIFO Underrun |
3 |
Data Transfer Error |
4 |
Descriptor Read Error |
5 |
Core Error |
Receive Channel Control Word
The receive channel control word consists of the following:
Mask |
Function |
0x00000001 |
Enable |
0x000000FE |
Frame Offset |
0x00000100 |
Direct FIFO Receive Mode (PIO) |
0x00030000 |
Address Extension Bits |
Receive Channel Status - State
The receive channel status state word consists of the following:
Mask |
Function |
0x00001FFF |
Current Descriptor Pointer |
0xF0000000 |
Receive State |
Receive State
This field can take the following values:
Value |
Meaning |
0 |
Disabled |
1 |
Active |
2 |
Idle Wait |
3 |
Stopped |
4 |
Suspend Pending |
Receive Channel Status - Errors
The receive channel status word consists of the following:
Mask |
Function |
0x0001FFFF |
Active Descriptor Pointer |
0xF0000000 |
Receive Errors |
Receive Errors
This field can take the following values:
Value |
Meaning |
0 |
No Error |
1 |
Descriptor Protocol Error (Indicates the Descriptor Ring Address could not be accessed) |
2 |
Data FIFO Overflow |
3 |
Data Transfer Error |
4 |
Descriptor Read Error |
5 |
Core Error |
Descriptors
Each descriptor (that is stored into the descriptor ring and posted) contains of four 4 byte fields:
64 Bit DMA Descriptor |
Control 1 - Control and Buffer Count |
Control 2 - Buffer Count and Address Extension |
Address 1 - Low bits of memory address of data buffer |
Address 2 - High bits of memory address of data buffer |
(in this order). The descriptor is never modified by the hardware, only read by it.
Control 1
Control field 1 breaks down as such:
0x10000000 |
End of Descriptor Table |
0x20000000 |
Interrupt on Completetion Requested |
0x40000000 |
End of Frame |
0x80000000 |
Start of Frame |
Control 2
Control field 2 breaks down as such:
Mask |
Function |
0x00001FFF |
Buffer Byte Count |
0x00030000 |
Address Extension Bits |
The meaning of the flags at the high 4 bits of the control 1 field is clear when you consider scatter-gather-I/O. Each transfer can be posted into or read from multiple buffers. The start of frame flag indicates that this transfer starts a new I/O packet, end of frame indicates that this is the last buffer for one packet.
The interrupt on completion flag signals (if turned on) that an interrupt is requested when this single transfer (not packet) is completed, end of descriptor table is used to signal to the chip that no valid descriptors follow in the memory after this one but that the controller should rather start reading at the beginning of the descriptor ring again.
The address 2 field is as follows (address 1 contains all address bits):
Mask |
Function |
0x3FFFFFFF |
Address |
0xC0000000 |
Routing |
Known values for the routing value are as follows:
Value |
Function |
0 |
No translation |
2 |
Client Mode Translation (2 Zettabytes) |
If you have enabled any routing bits, make sure to also set the address extension bits in the control field when setting the address. This allows use of the full 64 bits of address space.
Working with the DMA Engine
DMA Engine Initialization
- Allocate enough DMA-able memory for the transmit and receiving descriptor rings and however many descriptors you want to fit into them. Make sure they are 4/8K-page-aligned and not larger than 4/8K.
- Zero out the descriptor rings
(If applicable) set the transmit control register to have only transmit enable set, set the transmit descriptor ring address.
- (If applicable) set the receive descriptor ring address (since no receive buffers have been posted yet, you cannot change the control register).
Transfer DMA Initialization
- Clear the Transmit Descriptor Ring
- Set the transfer enable bit in the Transmit Control Register
- Write the bus address of the transfer descriptor ring to the Transmit Address Register
Receive DMA Initialization
- Clear the Receive Descriptor Ring
- Set the receive enable bit in the Receive Control Register
- Write the bus address of the receive descriptor ring to the Receive Address Register
Suspend the Transfer DMA
Set the PowerSavingControlBits bit 26 and calculate bit 25
- Set the Suspend Request register in the Transmit Control Register
Resume the Transfer DMA
- Unset the Suspend Request register in the Transmit Control Register
Calculate both of the PowerSavingControlBits
Reset Transfer DMA
- Spinwait for up to 10 mSec, or until the DMA transmit status register is set to disabled, idle or stopped
- Write 0 to the Transmit DMA control register
- Spinwait for up to 10 mSec or until the DMA transmit status register is set to disabled
- If the status is still not disabled, an error has occured
- Delay for 300 uSec to ensure that the reset was completed
Reset Receiving DMA
- Write 0 to the Receive DMA control register
- Spinwait for up to 10 mSec or until the DMA receive status register is set to disabled
- If the status is still not disabled, an error has occured
Disabling the DMA Engine
- Disabling is as simple as freeing the DMA descriptor rings
Transmitting (To the Wireless Core)
Now you already know almost everything you need to transfer stuff.
- For each piece of the packet to be transferred, get a descriptor and set its properties to the correct values. If you need, ask for interrupts but you probably should only do that on the last descriptor of one packet.
Write the first descriptor offset the engine should not process (for the 10th descriptor this is 80) to the descriptor stop index register of the transmit channel (that is, the last used offset+1 handling wrap-around).
Receiving (From the Wireless Core)
When some data is received, the 802.11 core gives this data to the DMA engine. Additionally, a receive header (see FrameInformation) is given to the DMA engine as well. The receive header is put into the space before the frame offset (which is why the frame offset should be 30), and the actual data is put after that. I don't know what happens if the frame offset is chosen too small, maybe then the data overwrites the header. Additionally, the DMA engine prepends the length of the payload (frame offset + data length). If one descriptor is too small, the data is split over multiple rx descriptors, ignoring the frame offset in the next descriptors (I think). The original driver ignores packets that don't fit into one descriptor, skipping them and the extra descriptors that belong to it. Every packet gets its own descriptor(s).
DMA Interrupts
Each DMA controller is linked to the interrupt reason registers in the MMIO area 0x20 - 0x38. They contain the following flags (incomplete):
bits |
|||||||||||||||||||||||||||||||
31 |
.. |
17 |
16 |
15 |
.. |
10 |
9 |
... |
0 |
||||||||||||||||||||||
unknown |
DMA receive done |
chiperrors |
unknown |
Chip Errors
The chiperrors field is a bunch of flags:
bits |
|||||
5 |
4 |
3 |
2 |
1 |
0 |
unknown,fatal |
unknown,fatal |
unknown, not fatal |
unknown,fatal |
unknown,fatal |
unknown,fatal |
If a fatal error occurs, you need to reset the chip (80211CoreReset followed by 80211Init). In some cases it might suffice to reset the DMA queues for example, but we don't know that.
DMA Parameters for the Wireless Core
On the wireless core, out of the 6 DMA engines only the first is used for receiving data, and only the first 5 are even attached. On cores with revision < 5, the fourth DMA engine is also used, but it's only used for receiving control packets. If the 4th DMA engine is used, its parameters are described below. All others can under certain circumstances be used for sending, but only in access point mode. In station mode, always use the second DMA engine for sending packets.
The first receive part should have a frame offset of 30 bytes, the last doesn't use a frame offset. You should always keep about 16 receive descriptors posted to the chip, on the first engine their buffer sizes should not be below 1792 bytes, on the last one 16 bytes suffice.
As a rule of thumb, reserve about 256 transmit descriptors. But it doesn't really matter, the page alignment requirements makes you reserve more memory anyway unless you want to re-use the rest of that page for receive buffers.