axidma
Vitis Drivers API Documentation
axidma Documentation

This is the driver API for the AXI DMA engine.For a full description of DMA features, please see the hardware spec. This driver supports the following features:

  • Scatter-Gather DMA (SGDMA)
  • Simple DMA
  • Interrupts
  • Programmable interrupt coalescing for SGDMA
  • APIs to manage Buffer Descriptors (BD) movement to and from the SGDMA engine

Simple DMA

Simple DMA allows the application to define a single transaction between DMA and Device. It has two channels: one from the DMA to Device and the other from Device to DMA. Application has to set the buffer address and length fields to initiate the transfer in respective channel.

Transactions

The object used to describe a transaction is referred to as a Buffer Descriptor (BD). Buffer descriptors are allocated in the user application. The user application needs to set buffer address, transfer length, and control information for this transfer. The control information includes SOF and EOF. Definition of those masks are in xaxidma_hw.h

Scatter-Gather DMA

SGDMA allows the application to define a list of transactions in memory which the hardware will process without further application intervention. During this time, the application is free to continue adding more work to keep the Hardware busy.

User can check for the completion of transactions through polling the hardware, or interrupts.

SGDMA processes whole packets. A packet is defined as a series of data bytes that represent a message. SGDMA allows a packet of data to be broken up into one or more transactions. For example, take an Ethernet IP packet which consists of a 14 byte header followed by a 1 or more bytes of payload. With SGDMA, the application may point a BD to the header and another BD to the payload, then transfer them as a single message. This strategy can make a TCP/IP stack more efficient by allowing it to keep packet header and data in different memory regions instead of assembling packets into contiguous blocks of memory.

BD Ring Management

BD rings are shared by the software and the hardware.

The hardware expects BDs to be setup as a linked list. The DMA hardware walks through the list by following the next pointer field of a completed BD. The hardware stops processing when the just completed BD is the same as the BD specified in the Tail Ptr register in the hardware.

The last BD in the ring is linked to the first BD in the ring.

All BD management are done inside the driver. The user application should not directly modify the BD fields. Modifications to the BD fields should always go through the specific API functions.

Within the ring, the driver maintains four groups of BDs. Each group consists of 0 or more adjacent BDs:

  • Free: The BDs that can be allocated by the application with XAxiDma_BdRingAlloc().
  • Pre-process: The BDs that have been allocated with XAxiDma_BdRingAlloc(). These BDs are under application control. The application modifies these BDs through driver API to prepare them for DMA transactions.
  • Hardware: The BDs that have been enqueued to hardware with XAxiDma_BdRingToHw(). These BDs are under hardware control and may be in a state of awaiting hardware processing, in process, or processed by hardware. It is considered an error for the application to change BDs while they are in this group. Doing so can cause data corruption and lead to system instability.
  • Post-process: The BDs that have been processed by hardware and have been extracted from the Hardware group with XAxiDma_BdRingFromHw(). These BDs are under application control. The application can check the transfer status of these BDs. The application use XAxiDma_BdRingFree() to put them into the Free group.

BDs are expected to transition in the following way for continuous DMA transfers:

        XAxiDma_BdRingAlloc()                   XAxiDma_BdRingToHw()
  Free ------------------------> Pre-process ----------------------> Hardware
                                                                     |
   /|\                                                               |
    |   XAxiDma_BdRingFree()                  XAxiDma_BdRingFromHw() |
    +--------------------------- Post-process <----------------------+

When a DMA transfer is to be cancelled before enqueuing to hardware, application can return the requested BDs to the Free group using XAxiDma_BdRingUnAlloc(), as shown below:

        XAxiDma_BdRingUnAlloc()
  Free <----------------------- Pre-process

The API provides functions for BD list traversal:

These functions should be used with care as they do not understand where one group ends and another begins.

SGDMA Descriptor Ring Creation

BD ring is created using XAxiDma_BdRingCreate(). The memory for the BD ring is allocated by the application, and it has to be contiguous. Physical address is required to setup the BD ring.

The application can use XAxiDma_BdRingMemCalc() to find out the amount of memory needed for a certain number of BDs. XAxiDma_BdRingCntCalc() can be used to find out how many BDs can be allocated for certain amount of memory.

A helper function, XAxiDma_BdRingClone(), can speed up the BD ring setup if the BDs have same types of controls, for example, SOF and EOF. After using the XAxiDma_BdRingClone(), the application only needs to setup the buffer address and transfer length. Note that certain BDs in one packet, for example, the first BD and the last BD, may need to setup special control information.

Descriptor Ring State Machine

There are two states of the BD ring:

  • HALTED (H), where hardware is not running
  • NOT HALTED (NH), where hardware is running

The following diagram shows the state transition for the DMA engine:

  _____ XAxiDma_StartBdRingHw(), or XAxiDma_BdRingStart(),   ______
  |   |               or XAxiDma_Resume()                    |    |
  | H |----------------------------------------------------->| NH |
  |   |<-----------------------------------------------------|    |
  -----   XAxiDma_Pause() or XAxiDma_Reset()                 ------

Interrupt Coalescing

SGDMA provides control over the frequency of interrupts through interrupt coalescing. The DMA engine provides two ways to tune the interrupt coalescing:

  • The packet threshold counter. Interrupt will fire once the programmable number of packets have been processed by the engine.
  • The packet delay timer counter. Interrupt will fire once the programmable amount of time has passed after processing the last packet, and no new packets to process. Note that the interrupt will only fire if at least one packet has been processed.

Interrupt

Interrupts are handled by the user application. Each DMA channel has its own interrupt ID. The driver provides APIs to enable/disable interrupt, and tune the interrupt frequency regarding to packet processing frequency.

Software Initialization

To use the Simple mode DMA engine for transfers, the following setup is required:

  • DMA Initialization using XAxiDma_CfgInitialize() function. This step initializes a driver instance for the given DMA engine and resets the engine.
  • Enable interrupts if chosen to use interrupt mode. The application is responsible for setting up the interrupt system, which includes providing and connecting interrupt handlers and call back functions, before enabling the interrupts.
  • Set the buffer address and length field in respective channels to start the DMA transfer

To use the SG mode DMA engine for transfers, the following setup are required:

  • DMA Initialization using XAxiDma_CfgInitialize() function. This step initializes a driver instance for the given DMA engine and resets the engine.
  • BD Ring creation. A BD ring is needed per DMA channel and can be built by calling XAxiDma_BdRingCreate().
  • Enable interrupts if chose to use interrupt mode. The application is responsible for setting up the interrupt system, which includes providing and connecting interrupt handlers and call back functions, before enabling the interrupts.
  • Start a DMA transfer: Call XAxiDma_BdRingStart() to start a transfer for the first time or after a reset, and XAxiDma_BdRingToHw() if the channel is already started. Calling XAxiDma_BdRingToHw() when a DMA channel is not running will not put the BDs to the hardware, and the BDs will be processed later when the DMA channel is started through XAxiDma_BdRingStart().

How to start DMA transactions

The user application uses XAxiDma_BdRingToHw() to submit BDs to the hardware to start DMA transfers.

For both channels, if the DMA engine is currently stopped (using XAxiDma_Pause()), the newly added BDs will be accepted but not processed until the DMA engine is started, using XAxiDma_BdRingStart(), or resumed, using XAxiDma_Resume().

Software Post-Processing on completed DMA transactions

If the interrupt system has been set up and the interrupts are enabled, a DMA channels notifies the software about the completion of a transfer through interrupts. Otherwise, the user application can poll for completions of the BDs, using XAxiDma_BdRingFromHw() or XAxiDma_BdHwCompleted().

  • Once BDs are finished by a channel, the application first needs to fetch them from the channel using XAxiDma_BdRingFromHw().
  • On the TX side, the application now could free the data buffers attached to those BDs as the data in the buffers has been transmitted.
  • On the RX side, the application now could use the received data in the buffers attached to those BDs.
  • For both channels, completed BDs need to be put back to the Free group using XAxiDma_BdRingFree(), so they can be used for future transactions.
  • On the RX side, it is the application's responsibility to have BDs ready to receive data at any time. Otherwise, the RX channel refuses to accept any data if it has no RX BDs.

Examples

We provide five examples to show how to use the driver API:

Address Translation

All buffer addresses and BD addresses for the hardware are physical addresses. The user application is responsible to provide physical buffer address for the BD upon BD ring creation. The user application accesses BD through its virtual address. The driver maintains the address translation between the physical and virtual address for BDs.

Cache Coherency

This driver expects all application buffers attached to BDs to be in cache coherent memory. If cache is used in the system, buffers for transmit MUST be flushed from the cache before passing the associated BD to this driver. Buffers for receive MUST be invalidated before accessing the data.

Alignment

For BDs:

Minimum alignment is defined by the constant XAXIDMA_BD_MINIMUM_ALIGNMENT. This is the smallest alignment allowed by both hardware and software for them to properly work.

If the descriptor ring is to be placed in cached memory, alignment also MUST be at least the processor's cache-line size. Otherwise, system instability occurs. For alignment larger than the cache line size, multiple cache line size alignment is required.

Aside from the initial creation of the descriptor ring (see XAxiDma_BdRingCreate()), there are no other run-time checks for proper alignment of BDs.

For application data buffers:

Application data buffers may reside on any alignment if DRE is built into the hardware. Otherwise, application data buffer must be word-aligned. The word is defined by XPAR_AXIDMA_0_M_AXIS_MM2S_TDATA_WIDTH for transmit and XPAR_AXIDMA_0_S_AXIS_S2MM_TDATA_WIDTH for receive.

For scatter gather transfers that have more than one BDs in the chain of BDs, Each BD transfer length must be multiple of word too. Otherwise, internal error happens in the hardware.

Error Handling

The DMA engine will halt on all error conditions. It requires the software to do a reset before it can start process new transfer requests.

Restart After Stopping

After the DMA engine has been stopped (through reset or reset after an error) the software keeps track of the current BD pointer when reset happens, and processing of BDs can be resumed through XAxiDma_BdRingStart().

Limitations

This driver does not have any mechanisms for mutual exclusion. It is up to the application to provide this protection.

Hardware Defaults & Exclusive Use

After the initialization or reset, the DMA engine is in the following default mode:

  • All interrupts are disabled.
  • Interrupt coalescing counter is 1.
  • The DMA engine is not running (halted). Each DMA channel is started separately, using XAxiDma_StartBdRingHw() if no BDs are setup for transfer yet, or XAxiDma_BdRingStart() otherwise.

The driver has exclusive use of the registers and BDs. All accesses to the registers and BDs should go through the driver interface.

Debug Print

To see the debug print for the driver, please put "-DDEBUG" as the extra compiler flags in software platform settings. Also comment out the line in xdebug.h: "#undef DEBUG".

Changes From v1.00a

. We have changes return type for XAxiDma_BdSetBufAddr() from void to int . We added XAxiDma_LookupConfig() so that user does not need to look for the hardware settings anymore.

MODIFICATION HISTORY:
Ver   Who  Date     Changes


1.00a jz 05/18/10 First release 2.00a jz 08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c, updated tcl file, added xaxidma_porting_guide.h 3.00a jz 11/22/10 Support IP core parameters change 4.00a rkv 02/22/11 Added support for simple DMA mode New API added for simple DMA mode are

  • XAxiDma_Busy
  • XAxiDma_SimpleTransfer New Macros added for simple DMA mode are
    • XAxiDma_HasSg
    • XAxiDma_IntrEnable
    • XAxiDma_IntrGetEnabled
    • XAxiDma_IntrDisable
    • XAxiDma_IntrGetIrq
    • XAxiDma_IntrAckIrq 5.00a srt 08/25/11 Added support for memory barrier and modified Cache Macros to have a common API for Microblaze and Zynq. 6.00a srt 01/24/12 Added support for Multi-Channel DMA mode.
Changed APIs:
                * XAxiDma_GetRxRing(InstancePtr, RingIndex)
                * XAxiDma_Start(XAxiDma * InstancePtr, int RingIndex)
                * XAxiDma_Started(XAxiDma * InstancePtr, int RingIndex)
                * XAxiDma_Pause(XAxiDma * InstancePtr, int RingIndex)
                * XAxiDma_Resume(XAxiDma * InstancePtr, int RingIndex)
                * XAxiDma_SimpleTransfer(XAxiDma InstancePtr,
                                        u32 BuffAddr, u32 Length,
                                        int Direction, int RingIndex)
                * XAxiDma_StartBdRingHw(XAxiDma_BdRing * RingPtr,
                                int RingIndex)
                * XAxiDma_BdRingStart(XAxiDma_BdRing * RingPtr,
                                         int RingIndex)
                * XAxiDma_BdRingToHw(XAxiDma_BdRing * RingPtr,
                        int NumBd, XAxiDma_Bd * BdSetPtr, int RingIndex)
                * XAxiDma_BdRingDumpRegs(XAxiDma_BdRing * RingPtr,
                                         int RingIndex)
                * XAxiDma_BdRingSnapShotCurrBd(XAxiDma_BdRing * RingPtr,
                                         int RingIndex)
                * XAxiDma_BdSetLength(XAxiDma_Bd *BdPtr,
                                u32 LenBytes, u32 LengthMask)
                * XAxiDma_BdGetActualLength(BdPtr, LengthMask)
                * XAxiDma_BdGetLength(BdPtr, LengthMask)

  • New APIs * XAxiDma_SelectKeyHole(XAxiDma *InstancePtr, int Direction, int Select) * XAxiDma_UpdateBdRingCDesc(XAxiDma_BdRing * RingPtr, int RingIndex) 7.00a srt 06/18/12 All the APIs changed in v6_00_a are reverted back for backward compatibility.
  • Changed the logic of MCDMA BD fields Set APIs, to clear the field first and then set it. 7.02a srt 01/23/13 Replaced *_TDATA_WIDTH parameters to *_DATA_WIDTH (CR 691867) Updated DDR base address for IPI designs (CR 703656). 8.0 adk 19/12/13 Updated as per the New Tcl API's srt 01/29/14 Added support for Micro DMA Mode and cyclic mode of operations.

New APIs:
                * XAxiDma_SelectCyclicMode(XAxiDma InstancePtr,
                                        int Direction, int Select)
                        * XAxiDma_BdSetBufAddrMicroMode(XAxiDma_Bd, u32)
8.1   adk  20/01/15  Added support for peripheral test. Created the self
               test example to include it on peripheral test's(CR#823144).
8.1   adk  29/01/15  Added the sefltest api (XAxiDma_Selftest) to the driver source files
                      (xaxidma_selftest.c) and called this from the selftest example
9.0     adk  27/07/15  Added support for 64-bit Addressing.
9.0   adk  19/08/15  Fixed CR#873125 DMA SG Mode example tests are failing on
               HW in 2015.3.
9.1   sk   11/10/15 Used UINTPTR instead of u32 for Baseaddress CR# 867425.
9.3   adk  26/07/16 Reduce the size of the buffer descriptor to 64 bytes.
      ms   01/23/17 Modified xil_printf statement in main function for all
           examples to ensure that "Successfully ran" and "Failed" strings
           are available in all examples. This is a fix for CR-965028.
      ms   03/17/17 Added readme.txt file in examples folder for doxygen
                    generation.
      ms   04/05/17 Modified Comment lines in functions to recognize
                    it as documentation block and added tabspace at return
                    statements in functions of axidma examples for proper
                    documentation while generating doxygen.
                    Modified readme file in examples folder.
9.4  adk   25/07/17 Added example for cyclic dma mode CR#974218.
     adk   08/08/17 Fixed CR#980607 Can't select individual AXI DMA code examples.
              Fixed compilation warning in the driver
9.5  adk   17/10/17 Fixed CR#987026 mulit packet example fails on A53.
             26/10/17 Fixed CR#987214 Fix race condition in the XAxiDma_Reset().
     rsp   11/01/17 Fixed CR#988210 Add interface to do config lookup based
                    on base address.
     adk   13/11/17 Fixed CR#989455 multi-channel interrupt example fails on A53.
9.6  rsp   01/11/18 Fixed CR#976392 In XAxiDma struct use UINTPTR for RegBase.
                    In XAxiDma_LookupConfigBaseAddr() use UINTPTR for Baseaddr.
9.7  rsp   04/25/18 Add SgLengthWidth member in dma config structure. CR #1000474
9.13 rsp   01/08/21 Fix compilation failure in XAxiDma_IntrGetEnabled().
9.15  sa   08/12/22 Updated the examples to use latest MIG cannoical define
                       i.e XPAR_MIG_0_C0_DDR4_MEMORY_MAP_BASEADDR.
     adk   08/16/22 Fix syntax error in the XAxiDma_BdRingGetCurrBd() API.