

<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.amigaos.net/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jamie+Krueger</id>
	<title>AmigaOS Documentation Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.amigaos.net/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jamie+Krueger"/>
	<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/wiki/Special:Contributions/Jamie_Krueger"/>
	<updated>2026-05-29T15:57:05Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=Resources&amp;diff=12375</id>
		<title>Resources</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=Resources&amp;diff=12375"/>
		<updated>2023-10-18T20:51:58Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* System Resources */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Resources are responsible for low-level hardware control, see [[Exec Resources]] to have a better insight of what it is and how it&#039;s used. &lt;br /&gt;
&lt;br /&gt;
== System Resources ==&lt;br /&gt;
&lt;br /&gt;
[[BattClock Resource]]&lt;br /&gt;
&lt;br /&gt;
[[BattMem Resource]]&lt;br /&gt;
&lt;br /&gt;
[[CIA Resource]]&lt;br /&gt;
&lt;br /&gt;
[[Disk Resource]]&lt;br /&gt;
&lt;br /&gt;
[[DMA Resource]]&lt;br /&gt;
&lt;br /&gt;
[[FileSystem Resource]]&lt;br /&gt;
&lt;br /&gt;
[[Misc Resource]]&lt;br /&gt;
&lt;br /&gt;
[[Potgo Resource]]&lt;br /&gt;
&lt;br /&gt;
[[PerformanceMonitor Resource]]&lt;br /&gt;
&lt;br /&gt;
[[Xena Resource]]&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Engine&amp;diff=12374</id>
		<title>DMA Engine</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Engine&amp;diff=12374"/>
		<updated>2023-10-18T20:50:15Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: Jamie Krueger moved page DMA Engine to DMA Resource: Renaming to reflect that this page covers the fsldma.resource API and not just a discussion of the underlined DMA Engine.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[DMA Resource]]&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=12373</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=12373"/>
		<updated>2023-10-18T20:50:15Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: Jamie Krueger moved page DMA Engine to DMA Resource: Renaming to reflect that this page covers the fsldma.resource API and not just a discussion of the underlined DMA Engine.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019, 2021 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example 1: &amp;quot;Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 1, &amp;quot;Blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using Virtual memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct fslDMAIFace *IfslDMA      = NULL;&lt;br /&gt;
  uint32             lSize         = 0;&lt;br /&gt;
  CONST_APTR         pSrc          = NULL;&lt;br /&gt;
  APTR               pDest         = NULL;&lt;br /&gt;
  BOOL               bGotResources = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set the size of our test buffers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE; // About 64 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IfslDMA) &amp;amp;&amp;amp; (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest) )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMA() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Wait for the transaction to complete before continuing.&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pSrc,pDest);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMA(pSrc,pDest,lSize) )&lt;br /&gt;
    {&lt;br /&gt;
      // Success - Do something with the copied data and quit&lt;br /&gt;
      printf(&amp;quot;Returned with Success.\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Report the error&lt;br /&gt;
      printf(&amp;quot;Received an Error!\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example 2: &amp;quot;Non-Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 2, &amp;quot;Non-blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using user notifications and Physical memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct ExecBase    *ExecBase          = (*(struct ExecBase **)4);&lt;br /&gt;
  struct MMUIFace    *IMMU              = NULL;&lt;br /&gt;
  struct fslDMAIFace *IfslDMA           = NULL;&lt;br /&gt;
  uint32             lSize              = 0;&lt;br /&gt;
  CONST_APTR         pSrc               = NULL;&lt;br /&gt;
  APTR               pDest              = NULL;&lt;br /&gt;
  CONST_APTR         pPhySrcAttr        = NULL;&lt;br /&gt;
  APTR               pPhyDstAttr        = NULL;&lt;br /&gt;
  int8               nSuccessSigNum     = -1;&lt;br /&gt;
  int8               nInProgressSigNum  = -1;&lt;br /&gt;
  int8               nErrorSigNum       = -1;&lt;br /&gt;
  uint32             lSuccessSigMask    = 0;&lt;br /&gt;
  uint32             lInProgressSigMask = 0;&lt;br /&gt;
  uint32             lErrorSigMask      = 0;&lt;br /&gt;
  uint32             lAllSigsMask       = 0;&lt;br /&gt;
  BOOL               bGotResources      = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the MMU Interface&lt;br /&gt;
  IMMU = (struct MMUIFace *)IExec-&amp;gt;GetInterface((struct Library *)ExecBase,&lt;br /&gt;
                                                &amp;quot;MMU&amp;quot;,1,NULL);&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set our test buffer size large enough to generate some sub-block transfers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE * 4; // About 256 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate signals to wait on&lt;br /&gt;
  nSuccessSigNum    = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nInProgressSigNum = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nErrorSigNum      = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
&lt;br /&gt;
  // Construct the signal masks we need to Wait() on later.&lt;br /&gt;
  // We are assuming these values are being built with&lt;br /&gt;
  // allocated signals here, but we will verify it before use.&lt;br /&gt;
  lSuccessSigMask    = (uint32)(1L &amp;lt;&amp;lt; nSuccessSigNum);&lt;br /&gt;
  lInProgressSigMask = (uint32)(1L &amp;lt;&amp;lt; nInProgressSigNum);&lt;br /&gt;
  lErrorSigMask      = (uint32)(1L &amp;lt;&amp;lt; nErrorSigNum);&lt;br /&gt;
  lAllSigsMask = (lSuccessSigMask | lInProgressSigMask | lErrorSigMask);&lt;br /&gt;
&lt;br /&gt;
  // Obtain the pointer to ourselves (this Task)&lt;br /&gt;
  struct Task *pThisTask = IExec-&amp;gt;FindTask(NULL);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IMMU) &amp;amp;&amp;amp; (NULL != IfslDMA) &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest)   &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pThisTask )                &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nSuccessSigNum)              &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nInProgressSigNum)           &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nErrorSigNum)                 )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // In this test we are using Physical memory areas&lt;br /&gt;
    // for both source and destination, so before we&lt;br /&gt;
    // hand the transaction to the DMA hardware, we first&lt;br /&gt;
    // need to set the flush the data cache, set the&lt;br /&gt;
    // buffers to cache-inhibited and obtain the Physical&lt;br /&gt;
    // addresses for both buffers&lt;br /&gt;
&lt;br /&gt;
    // Enter Supervisor Mode&lt;br /&gt;
    APTR pUserStack = IExec-&amp;gt;SuperState();&lt;br /&gt;
&lt;br /&gt;
    // Flush out any cache for our two buffers&lt;br /&gt;
    IExec-&amp;gt;CacheClearE((APTR)pSrc,lSize,CACRF_ClearD);&lt;br /&gt;
    IExec-&amp;gt;CacheClearE(pDest,lSize,CACRF_ClearD);&lt;br /&gt;
&lt;br /&gt;
    // Now set the memory attributes to prevent further cache operations&lt;br /&gt;
    uint32 lSrcMemAttrs = IMMU-&amp;gt;GetMemoryAttrs((APTR)pSrc,0);&lt;br /&gt;
    uint32 lDstMemAttrs = IMMU-&amp;gt;GetMemoryAttrs(pDest,0);&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs((APTR)pSrc,lSize,(lSrcMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs(pDest,lSize,(lDstMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
&lt;br /&gt;
    // Get the Physical addresses for our two buffers&lt;br /&gt;
    pPhySrcAttr = IMMU-&amp;gt;GetPhysicalAddress((APTR)pSrc);&lt;br /&gt;
    pPhyDstAttr = IMMU-&amp;gt;GetPhysicalAddress(pDest);&lt;br /&gt;
&lt;br /&gt;
    // Return to User Mode&lt;br /&gt;
    if ( NULL != pUserStack ) IExec-&amp;gt;UserState(pUserStack);&lt;br /&gt;
&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMATags() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Start off the transaction then wait on completion signals.&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Non-Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,&lt;br /&gt;
           lSize,pPhySrcAttr,pPhyDstAttr);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMATags(pPhySrcAttr,pPhyDstAttr,lSize,&lt;br /&gt;
                            FSLDMA_CM_SourceIsPhysical,          TRUE,&lt;br /&gt;
                            FSLDMA_CM_DestinationIsPhysical,     TRUE,&lt;br /&gt;
                            FSLDMA_CM_DoNotWait,                 TRUE,&lt;br /&gt;
                            FSLDMA_CM_NotifyTask,                pThisTask,&lt;br /&gt;
                            FSLDMA_CM_NotifySignalNumber,        nSuccessSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyProgessSignalNumber, nInProgressSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyErrorSignalNumber,   nErrorSigNum,&lt;br /&gt;
                            TAG_DONE) )&lt;br /&gt;
    {&lt;br /&gt;
      // If the above call sets up correctly, it returns immeditately&lt;br /&gt;
      // So do something here *while* the data is being copied...&lt;br /&gt;
      printf(&amp;quot;Doing other stuff before waiting...\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
      // Now we will Wait() for the completion signals from the DMA&lt;br /&gt;
      BOOL   bStillRunning = TRUE;&lt;br /&gt;
      uint32 lSigReceived  = 0;&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        // Wait for the DMA completion/status/error signals&lt;br /&gt;
        printf(&amp;quot;Waiting for signals...\n&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        lSigReceived = IExec-&amp;gt;Wait( lAllSigsMask | SIGBREAKF_CTRL_C );&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;In Progress&amp;quot; signal&lt;br /&gt;
        if ( lInProgressSigMask == (lSigReceived &amp;amp; lInProgressSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Do something on the &amp;quot;In Process&amp;quot; signal and continue...&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;In Progress\&amp;quot; signal...\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Success&amp;quot; signal&lt;br /&gt;
        if ( lSuccessSigMask == (lSigReceived &amp;amp; lSuccessSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Success - Do something with the copied data and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Completed Successfully\&amp;quot; signal.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Error&amp;quot; signal&lt;br /&gt;
        if ( lErrorSigMask == (lSigReceived &amp;amp; lErrorSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Report the error and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Error\&amp;quot; signal!\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Finally, check if we got a Break signal from the user&lt;br /&gt;
        // just in case we want to quit out early for some reason&lt;br /&gt;
        if ( SIGBREAKF_CTRL_C == (lSigReceived &amp;amp; SIGBREAKF_CTRL_C) )&lt;br /&gt;
        {&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;User break\&amp;quot; signal, ending.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
      } while( TRUE == bStillRunning );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  // Free any signals we (may have) obtained earlier&lt;br /&gt;
  if ( -1 != nSuccessSigNum    ) IExec-&amp;gt;FreeSignal(nSuccessSigNum);&lt;br /&gt;
  if ( -1 != nInProgressSigNum ) IExec-&amp;gt;FreeSignal(nInProgressSigNum);&lt;br /&gt;
  if ( -1 != nErrorSigNum      ) IExec-&amp;gt;FreeSignal(nErrorSigNum);&lt;br /&gt;
  // Release the MMU Interface (as needed)&lt;br /&gt;
  if ( NULL != IMMU ) IExec-&amp;gt;DropInterface((struct Interface *)IMMU);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;br /&gt;
&lt;br /&gt;
== Current fsldma.resource API release notes ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fsldma.resource 53.1 (30.9.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
- First release.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
fsldma.resource 53.2 (4.11.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
- Replaced the Busy Wait polling of the DMA Channel&lt;br /&gt;
  completion status with a fully event (interrupt)&lt;br /&gt;
  driven, multitasking task handler system.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
fsldma.resource 53.3 (22.11.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
- Reworked DMACopyMem() to properly handle normal&lt;br /&gt;
  cache-enabled virtual memory blocks using a&lt;br /&gt;
  combination of StartDMA()/EndDMA() and &amp;quot;CPU Snoop&amp;quot;&lt;br /&gt;
  mode on the DMA hardware.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
fsldma.resource 53.4 (4.12.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 - Major API rework and streamlining.&lt;br /&gt;
   Removed all other API calls save DMACopyMem().&lt;br /&gt;
   DMACopyMem() was renamed CopyMemDMA() and new&lt;br /&gt;
   TagItem based versions were added; CopyMemDMATagList()&lt;br /&gt;
   and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
   Seven new Tags were added to the API for use&lt;br /&gt;
   with the Tags version of CopyMemDMA. They enable&lt;br /&gt;
   using any combination of Virtual and Physical&lt;br /&gt;
   memory copies and support for new &amp;quot;Non-Blocking&amp;quot;&lt;br /&gt;
   transactions with user Notification via three&lt;br /&gt;
   possible signals; &amp;quot;Success&amp;quot;, &amp;quot;In Progress&amp;quot; and &amp;quot;Error.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   Several internal changes and improvements including&lt;br /&gt;
   but not limited to, streamlining internal signal&lt;br /&gt;
   handling between DMA Handler Tasks and user tasks&lt;br /&gt;
   and optimizing transactions using &amp;quot;Basic Chaining Mode.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   The DMA hardware&#039;s &amp;quot;Basic Chaining Mode&amp;quot; is now used&lt;br /&gt;
   internally to transfer larger single block sizes.&lt;br /&gt;
   Blocks greater than FSLDMA_OPTIMAL_BLKSIZE is size&lt;br /&gt;
   are transferred using &amp;quot;Basic Chaining Mode&amp;quot;, while&lt;br /&gt;
   blocks less than or equal to FSLDMA_OPTIMAL_BLKSIZE&lt;br /&gt;
   are transferred using &amp;quot;Basic Direct Mode.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   Previously, block sizes larger than FSLDMA_OPTIMAL_BLKSIZE&lt;br /&gt;
   were all transfered using a CPU driven loop of&lt;br /&gt;
   &amp;quot;Basic Direct Mode&amp;quot; transactions. This internal CPU&lt;br /&gt;
   driven loop has now been replaced by programming the&lt;br /&gt;
   hardware to perform a series of block transactions&lt;br /&gt;
   in a &amp;quot;Chain&amp;quot; as a single hardware transaction.&lt;br /&gt;
   This also enabled bringing out &amp;quot;Completed Successfully&amp;quot;,&lt;br /&gt;
   &amp;quot;In Progress&amp;quot; (a sub-block has transferred successfully)&lt;br /&gt;
   and &amp;quot;Error&amp;quot; signaling during &amp;quot;Non-Blocking&amp;quot; transactions.&lt;br /&gt;
&lt;br /&gt;
   Note:&lt;br /&gt;
     Currently only source and destination memory&lt;br /&gt;
     areas of the same type, Virtual-to-Virtual or&lt;br /&gt;
     Physical-to-Physical are supported.&lt;br /&gt;
&lt;br /&gt;
     Also, only Physical-to-Physical transactions&lt;br /&gt;
     support &amp;quot;Non-Blocking&amp;quot; transactions and User&lt;br /&gt;
     Notification signaling.&lt;br /&gt;
&lt;br /&gt;
     Future releases will remove these limitations.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=Autodocs:Main&amp;diff=12372</id>
		<title>Autodocs:Main</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=Autodocs:Main&amp;diff=12372"/>
		<updated>2023-10-18T19:49:21Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The autodocs are included in the latest [[SDK_FAQ|AmigaOS SDK]] and are also available as text files below:&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/a1floppy.doc.txt a1floppy.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/a1serial_dev.doc.txt a1serial_dev.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/AI_Driver.doc.txt AI_Driver.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/amigaguide.doc.txt amigaguide.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/amigaguide_dtc.doc.txt amigaguide_dtc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/AmigaInput.doc.txt AmigaInput.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/amiga_lib.doc.txt amiga_lib.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/animation_dtc.doc.txt animation_dtc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/application.doc.txt application.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/arexx_cl.doc.txt arexx_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/asl.doc.txt asl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/audio.doc.txt audio.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/battclock.doc.txt battclock.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/battmem.doc.txt battmem.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/bevel_ic.doc.txt bevel_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/biosversion.doc.txt biosversion.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/bitmap_ic.doc.txt bitmap_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/bsdsocket.doc.txt bsdsocket.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/btree.doc.txt btree.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/bullet.doc.txt bullet.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/button_gc.doc.txt button_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/camd.doc.txt camd.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/cardres.doc.txt cardres.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/cd.doc.txt cd.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/checkbox_gc.doc.txt checkbox_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/chooser_gc.doc.txt chooser_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/cia.doc.txt cia.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/clicktab_gc.doc.txt clicktab_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/clipboard.doc.txt clipboard.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/colorwheel_gc.doc.txt colorwheel_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/commodities.doc.txt commodities.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/console.doc.txt console.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/datatypes.doc.txt datatypes.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/datebrowser_gc.doc.txt datebrowser_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/ddebug_lib.doc.txt ddebug_lib.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/debug_lib.doc.txt debug_lib.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/diffview_gc.doc.txt diffview_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/disk.doc.txt disk.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/diskfont.doc.txt diskfont.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/diskio.doc.txt diskio.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/docky.doc.txt docky.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/dos.doc.txt dos.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/dos.dospackets.doc.txt dos.dospackets.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/dos.obsolete.doc.txt dos.obsolete.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/drawlist_ic.doc.txt drawlist_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/elf.doc.txt elf.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/exec.doc.txt exec.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/expansion.doc.txt expansion.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/filesysbox.doc.txt filesysbox.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/filesysres.doc.txt filesysres.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/filler_ic.doc.txt filler_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/fillrect_ic.doc.txt fillrect_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/frame_ic.doc.txt frame_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/frbutton_gc.doc.txt frbutton_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/fuelgauge_gc.doc.txt fuelgauge_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/gadget_gc.doc.txt gadget_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/gadtools.doc.txt gadtools.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/gameport.doc.txt gameport.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/Gameport_pci.doc.txt Gameport_pci.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/gauge_ic.doc.txt gauge_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/getcolor_gc.doc.txt getcolor_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/getfile_gc.doc.txt getfile_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/getfont_gc.doc.txt getfont_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/getscreenmode_gc.doc.txt getscreenmode_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/glyph_ic.doc.txt glyph_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/gradientslider_gc.doc.txt gradientslider_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/graphics.doc.txt graphics.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/group_gc.doc.txt group_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/hunk.doc.txt hunk.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/ibutton_gc.doc.txt ibutton_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/icon.doc.txt icon.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/iconmodule.doc.txt iconmodule.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/ic_cl.doc.txt ic_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/iffparse.doc.txt iffparse.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/image_ic.doc.txt image_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/input.doc.txt input.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/integer_gc.doc.txt integer_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/intuition.doc.txt intuition.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/iscroller_gc.doc.txt iscroller_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/istring_gc.doc.txt istring_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/itext_ic.doc.txt itext_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/keyboard.doc.txt keyboard.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/keymap.doc.txt keymap.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/label_ic.doc.txt label_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/layers.doc.txt layers.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/layout_gc.doc.txt layout_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/libamiga_a.doc.txt libamiga_a.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/listbrowser_gc.doc.txt listbrowser_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/locale.doc.txt locale.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/lowlevel.doc.txt lowlevel.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathffp.doc.txt mathffp.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathieeedoubbas.doc.txt mathieeedoubbas.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathieeedoubtrans.doc.txt mathieeedoubtrans.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathieeesingbas.doc.txt mathieeesingbas.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathieeesingtrans.doc.txt mathieeesingtrans.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathtrans.doc.txt mathtrans.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/menu_cl.doc.txt menu_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/misc.doc.txt misc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/model_cl.doc.txt model_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/narrator.doc.txt narrator.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/nonvolatile.doc.txt nonvolatile.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/openfirmware.doc.txt openfirmware.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/page_gc.doc.txt page_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/palette_gc.doc.txt palette_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/parallel.doc.txt parallel.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/partition_gc.doc.txt partition_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/penmap_ic.doc.txt penmap_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/performancemonitor.doc.txt performancemonitor.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/Picasso96API.doc.txt Picasso96API.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/picture_dtc.doc.txt picture_dtc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/pointer_cl.doc.txt pointer_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/popupmenu_cl.doc.txt popupmenu_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/potgo.doc.txt potgo.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/printer.doc.txt printer.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/prop_gc.doc.txt prop_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/radiobutton_gc.doc.txt radiobutton_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/realtime.doc.txt realtime.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/requester_cl.doc.txt requester_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/resource.doc.txt resource.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/rexxsyslib.doc.txt rexxsyslib.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/root_cl.doc.txt root_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/scroller_gc.doc.txt scroller_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/serial_dev.doc.txt serial_dev.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/sketchboard_gc.doc.txt sketchboard_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/slider_gc.doc.txt slider_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/sound_dtc.doc.txt sound_dtc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/space_gc.doc.txt space_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/speedbar_gc.doc.txt speedbar_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/string_gc.doc.txt string_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/sys_ic.doc.txt sys_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/tapedeck_gc.doc.txt tapedeck_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/textclip.doc.txt textclip.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/texteditor_gc.doc.txt texteditor_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/text_dtc.doc.txt text_dtc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/timer.doc.txt timer.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/timesync.doc.txt timesync.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/timezone.doc.txt timezone.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/trackdisk.doc.txt trackdisk.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/translator.doc.txt translator.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/usbfd.doc.txt usbfd.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/usbhcd.doc.txt usbhcd.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/usbresource.doc.txt usbresource.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/usbsys.doc.txt usbsys.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/utility.doc.txt utility.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/virtual_gc.doc.txt virtual_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/warp3d.doc.txt warp3d.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/window_cl.doc.txt window_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/workbench.doc.txt workbench.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/xenares.doc.txt xenares.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/z.doc.txt z.doc]&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=Debug_Logging_on_AmigaOS&amp;diff=12100</id>
		<title>Debug Logging on AmigaOS</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=Debug_Logging_on_AmigaOS&amp;diff=12100"/>
		<updated>2021-12-14T21:54:01Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* The Debug Logging Template */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Debug]]&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
The sole purpose of this article is to introduce developers that may be new to AmigaOS to its debug logging function. The Exec library has a function called DebugPrintF() that provides a printf() like API for outputting text to a debug buffer. This buffer can be dumped to disk via the dumpdebugbuffer command, or it can be redirected to a serial port. The debug buffer can survive a warm-reboot so its contents can be recovered after most crashes (so long as the machine does not require a complete reset). &lt;br /&gt;
&lt;br /&gt;
In brief:&lt;br /&gt;
&lt;br /&gt;
* IExec-&amp;gt;DebugPrintF() uses the same syntax as printf() and outputs to a debug buffer,&lt;br /&gt;
* The debug buffer can either be directed to memory (the default), or to the serial port. See the documentation for kdebug in the sys:documentation/kernel drawer of AmigaOS, and&lt;br /&gt;
* The debug buffer in memory can be saved to disk and cleared via: dumpdebugbuffer log.txt clear.&lt;br /&gt;
&lt;br /&gt;
For those who are experienced programmers, the details above are probably all that you require; for everyone else, read on to see how and why debug logging is important, and how it can be used.&lt;br /&gt;
&lt;br /&gt;
= The Importance of Debug Logging =&lt;br /&gt;
&lt;br /&gt;
Developing software is a complex task. The more functions, if/else calls and loops that a program has, the more complicated its operation becomes. Sooner or later it becomes necessary to examine what a program is doing internally. Many compilers (including GCC on AmigaOS) come with debuggers that allow one to step through a program line by line. However, this can be extremely tedious and is also unsuitable for any program that requires real-time operation. For example, it may be impossible to debug a game by stepping through the code because it has to respond to a player&#039;s joystick input (which changes which parts of the program are executed). Regardless, it is useful to provide a log of significant events in a program&#039;s operation. See the debug logs output for the RadeonHD driver [http://hdrlab.org.nz/radeonhd-first-screen/ here] and [http://hdrlab.org.nz/successful-radeon-hd-2400-pro-mode-setting-test/ here], as examples.&lt;br /&gt;
&lt;br /&gt;
So, what should be logged. Essentially, this is up to you, the programmer. Whatever information you think will be useful in tracking down bugs/issues, should be logged. Often it would be nice to have a hierarchy of debug levels so that it is not necessary to wade through huge debug files when only high-level information (e.g., warnings and errors) are required. I have created a debug module with a template makefile and test code precisely for this purpose.&lt;br /&gt;
&lt;br /&gt;
= The Debug Logging Template =&lt;br /&gt;
&lt;br /&gt;
The debug logging module provides a framework for multi-level debug logging. By providing a debug level, it is possible to specify what level of logging is required. An example executable (DebugLoggingTest) and makefile have been provided that show how to use the module.&lt;br /&gt;
&lt;br /&gt;
== USING THE DEBUG LOGGING MODULE ==&lt;br /&gt;
&lt;br /&gt;
The easiest way to learn how to use the debug module is to simply [[Media:DebugLogging.lha|download the template file]] and look at the provided makefile. After initial download the template is configured to output all debug messages. Type make, and then DebugLoggingTest. Now enter dumpdebugbuffer log.txt clear. Examining log.txt will show all the output messages, each of which can be matched to dprintf() calls in DebugLoggingTest.c. &lt;br /&gt;
&lt;br /&gt;
In the makefile there are three lines containing &amp;quot;CFLAGS.&amp;quot; Two of them are commented out (with a # character). The example code can be reconfigured to the other two modes by uncommenting the desired line, and commenting out the other two. Remember to perform a &amp;quot;make clean&amp;quot; before recompiling after making any change to the makefile. The most interesting configuration is the last one. In this configuration the user can enter a debug log level on the command line (e.g., &amp;quot;DebugLoggingTest 10&amp;quot;) and thus choose how much debug information is to be output.&lt;br /&gt;
&lt;br /&gt;
To use the debug module in other programs:&lt;br /&gt;
&lt;br /&gt;
* Set the TARGET variable in the makefile to the name of the appliation,&lt;br /&gt;
* compile files with the appropriate DEBUG flags set:&lt;br /&gt;
** -DTARGET=&amp;quot;$(TARGET)&amp;quot;, and&lt;br /&gt;
** -DDEBUG and (optionally) -DDEBUG_LOGLEVEL, or, -DVARLEVEL_DEBUG.&lt;br /&gt;
* Insert dprintf() calls into the program where appropriate (e.g., dprintf(DBG_CRITICAL, &amp;quot;A critical error occurred.\n&amp;quot;);), and&lt;br /&gt;
* the LOG_FUNCTION or LOG_FUNCENTRY/LOG_FUNCEXIT macros could also be useful.&lt;br /&gt;
&lt;br /&gt;
== DOCUMENTATION ==&lt;br /&gt;
&lt;br /&gt;
The debug module/template expects TARGET to be defined as a string giving the name of the program (e.g., in the makefile use -DTARGET=&amp;quot;AppName&amp;quot;). It provides two functions:&lt;br /&gt;
&lt;br /&gt;
* dprintf(debugLevel, fmt, ...) whichoutputs debug messages formatted printf style and adds a header giving the application name and the debug level of the message, and&lt;br /&gt;
* dprintf_cont(debugLevel, fmt, ...) also outputs debug messages, but minus the header (so that more complicated messages can be output).&lt;br /&gt;
&lt;br /&gt;
Several debug levels have been predefined:&lt;br /&gt;
&lt;br /&gt;
* DBG_CRITICAL for critical errors,&lt;br /&gt;
* DBG_WARNING for warnings,&lt;br /&gt;
* DBG_INFO for more detailed information,  &lt;br /&gt;
* DBG_FUNCTIONCALL which should be used for identifying function calls, and&lt;br /&gt;
* DBG_INTERNALINFO for even more detailed information&lt;br /&gt;
&lt;br /&gt;
There are also three modes of operation. If DEBUG is defined alone, it will output all debug messages. If, DEBUG_LOGLEVEL is set to a number, all messages will be output that have a debug level at or below that value. Finally, if VARLEVEL_DEBUG is defined, the user (or external code) can set the debug logging level on demand; in this case, the following two functions are defined:&lt;br /&gt;
&lt;br /&gt;
* void setDebugLevel(int debugLevel) which sets the debug logging level, and&lt;br /&gt;
* int getDebugLevel() which returns the currently set logging level.&lt;br /&gt;
&lt;br /&gt;
An example debug log message would be:&lt;br /&gt;
&lt;br /&gt;
 DebugLoggingTest (0): An example critical error&lt;br /&gt;
&lt;br /&gt;
There are also three macros defined that are useful for monitoring function entries and exits:&lt;br /&gt;
&lt;br /&gt;
* LOG_FUNCTION logs the name of the function that was called,&lt;br /&gt;
* LOG_FUNCENTRY logs the entry to a function, but is useful to put at the top of a function, and&lt;br /&gt;
* LOG_FUNCEXIT should be put before any return statement, it logs a funciton exit. &lt;br /&gt;
&lt;br /&gt;
LOG_FUNCENTRY and LOG_FUNCEXIT should be used together.&lt;br /&gt;
&lt;br /&gt;
== DOWNLOAD ==&lt;br /&gt;
&lt;br /&gt;
[[Media:DebugLogging.lha|The debug logging module and template.]]&lt;br /&gt;
&lt;br /&gt;
= Author =&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2008 Hans de Ruiter.&amp;lt;br/&amp;gt;&lt;br /&gt;
Reproduced with permission.&amp;lt;br/&amp;gt;&lt;br /&gt;
See the original article [http://hdrlab.org.nz/articles/amiga-os-articles/debug-logging/ here].&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=12099</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=12099"/>
		<updated>2021-12-10T18:09:24Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019, 2021 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example 1: &amp;quot;Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 1, &amp;quot;Blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using Virtual memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct fslDMAIFace *IfslDMA      = NULL;&lt;br /&gt;
  uint32             lSize         = 0;&lt;br /&gt;
  CONST_APTR         pSrc          = NULL;&lt;br /&gt;
  APTR               pDest         = NULL;&lt;br /&gt;
  BOOL               bGotResources = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set the size of our test buffers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE; // About 64 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IfslDMA) &amp;amp;&amp;amp; (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest) )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMA() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Wait for the transaction to complete before continuing.&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pSrc,pDest);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMA(pSrc,pDest,lSize) )&lt;br /&gt;
    {&lt;br /&gt;
      // Success - Do something with the copied data and quit&lt;br /&gt;
      printf(&amp;quot;Returned with Success.\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Report the error&lt;br /&gt;
      printf(&amp;quot;Received an Error!\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example 2: &amp;quot;Non-Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 2, &amp;quot;Non-blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using user notifications and Physical memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct ExecBase    *ExecBase          = (*(struct ExecBase **)4);&lt;br /&gt;
  struct MMUIFace    *IMMU              = NULL;&lt;br /&gt;
  struct fslDMAIFace *IfslDMA           = NULL;&lt;br /&gt;
  uint32             lSize              = 0;&lt;br /&gt;
  CONST_APTR         pSrc               = NULL;&lt;br /&gt;
  APTR               pDest              = NULL;&lt;br /&gt;
  CONST_APTR         pPhySrcAttr        = NULL;&lt;br /&gt;
  APTR               pPhyDstAttr        = NULL;&lt;br /&gt;
  int8               nSuccessSigNum     = -1;&lt;br /&gt;
  int8               nInProgressSigNum  = -1;&lt;br /&gt;
  int8               nErrorSigNum       = -1;&lt;br /&gt;
  uint32             lSuccessSigMask    = 0;&lt;br /&gt;
  uint32             lInProgressSigMask = 0;&lt;br /&gt;
  uint32             lErrorSigMask      = 0;&lt;br /&gt;
  uint32             lAllSigsMask       = 0;&lt;br /&gt;
  BOOL               bGotResources      = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the MMU Interface&lt;br /&gt;
  IMMU = (struct MMUIFace *)IExec-&amp;gt;GetInterface((struct Library *)ExecBase,&lt;br /&gt;
                                                &amp;quot;MMU&amp;quot;,1,NULL);&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set our test buffer size large enough to generate some sub-block transfers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE * 4; // About 256 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate signals to wait on&lt;br /&gt;
  nSuccessSigNum    = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nInProgressSigNum = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nErrorSigNum      = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
&lt;br /&gt;
  // Construct the signal masks we need to Wait() on later.&lt;br /&gt;
  // We are assuming these values are being built with&lt;br /&gt;
  // allocated signals here, but we will verify it before use.&lt;br /&gt;
  lSuccessSigMask    = (uint32)(1L &amp;lt;&amp;lt; nSuccessSigNum);&lt;br /&gt;
  lInProgressSigMask = (uint32)(1L &amp;lt;&amp;lt; nInProgressSigNum);&lt;br /&gt;
  lErrorSigMask      = (uint32)(1L &amp;lt;&amp;lt; nErrorSigNum);&lt;br /&gt;
  lAllSigsMask = (lSuccessSigMask | lInProgressSigMask | lErrorSigMask);&lt;br /&gt;
&lt;br /&gt;
  // Obtain the pointer to ourselves (this Task)&lt;br /&gt;
  struct Task *pThisTask = IExec-&amp;gt;FindTask(NULL);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IMMU) &amp;amp;&amp;amp; (NULL != IfslDMA) &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest)   &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pThisTask )                &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nSuccessSigNum)              &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nInProgressSigNum)           &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nErrorSigNum)                 )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // In this test we are using Physical memory areas&lt;br /&gt;
    // for both source and destination, so before we&lt;br /&gt;
    // hand the transaction to the DMA hardware, we first&lt;br /&gt;
    // need to set the flush the data cache, set the&lt;br /&gt;
    // buffers to cache-inhibited and obtain the Physical&lt;br /&gt;
    // addresses for both buffers&lt;br /&gt;
&lt;br /&gt;
    // Enter Supervisor Mode&lt;br /&gt;
    APTR pUserStack = IExec-&amp;gt;SuperState();&lt;br /&gt;
&lt;br /&gt;
    // Flush out any cache for our two buffers&lt;br /&gt;
    IExec-&amp;gt;CacheClearE((APTR)pSrc,lSize,CACRF_ClearD);&lt;br /&gt;
    IExec-&amp;gt;CacheClearE(pDest,lSize,CACRF_ClearD);&lt;br /&gt;
&lt;br /&gt;
    // Now set the memory attributes to prevent further cache operations&lt;br /&gt;
    uint32 lSrcMemAttrs = IMMU-&amp;gt;GetMemoryAttrs((APTR)pSrc,0);&lt;br /&gt;
    uint32 lDstMemAttrs = IMMU-&amp;gt;GetMemoryAttrs(pDest,0);&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs((APTR)pSrc,lSize,(lSrcMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs(pDest,lSize,(lDstMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
&lt;br /&gt;
    // Get the Physical addresses for our two buffers&lt;br /&gt;
    pPhySrcAttr = IMMU-&amp;gt;GetPhysicalAddress((APTR)pSrc);&lt;br /&gt;
    pPhyDstAttr = IMMU-&amp;gt;GetPhysicalAddress(pDest);&lt;br /&gt;
&lt;br /&gt;
    // Return to User Mode&lt;br /&gt;
    if ( NULL != pUserStack ) IExec-&amp;gt;UserState(pUserStack);&lt;br /&gt;
&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMATags() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Start off the transaction then wait on completion signals.&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Non-Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,&lt;br /&gt;
           lSize,pPhySrcAttr,pPhyDstAttr);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMATags(pPhySrcAttr,pPhyDstAttr,lSize,&lt;br /&gt;
                            FSLDMA_CM_SourceIsPhysical,          TRUE,&lt;br /&gt;
                            FSLDMA_CM_DestinationIsPhysical,     TRUE,&lt;br /&gt;
                            FSLDMA_CM_DoNotWait,                 TRUE,&lt;br /&gt;
                            FSLDMA_CM_NotifyTask,                pThisTask,&lt;br /&gt;
                            FSLDMA_CM_NotifySignalNumber,        nSuccessSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyProgessSignalNumber, nInProgressSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyErrorSignalNumber,   nErrorSigNum,&lt;br /&gt;
                            TAG_DONE) )&lt;br /&gt;
    {&lt;br /&gt;
      // If the above call sets up correctly, it returns immeditately&lt;br /&gt;
      // So do something here *while* the data is being copied...&lt;br /&gt;
      printf(&amp;quot;Doing other stuff before waiting...\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
      // Now we will Wait() for the completion signals from the DMA&lt;br /&gt;
      BOOL   bStillRunning = TRUE;&lt;br /&gt;
      uint32 lSigReceived  = 0;&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        // Wait for the DMA completion/status/error signals&lt;br /&gt;
        printf(&amp;quot;Waiting for signals...\n&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        lSigReceived = IExec-&amp;gt;Wait( lAllSigsMask | SIGBREAKF_CTRL_C );&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;In Progress&amp;quot; signal&lt;br /&gt;
        if ( lInProgressSigMask == (lSigReceived &amp;amp; lInProgressSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Do something on the &amp;quot;In Process&amp;quot; signal and continue...&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;In Progress\&amp;quot; signal...\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Success&amp;quot; signal&lt;br /&gt;
        if ( lSuccessSigMask == (lSigReceived &amp;amp; lSuccessSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Success - Do something with the copied data and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Completed Successfully\&amp;quot; signal.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Error&amp;quot; signal&lt;br /&gt;
        if ( lErrorSigMask == (lSigReceived &amp;amp; lErrorSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Report the error and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Error\&amp;quot; signal!\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Finally, check if we got a Break signal from the user&lt;br /&gt;
        // just in case we want to quit out early for some reason&lt;br /&gt;
        if ( SIGBREAKF_CTRL_C == (lSigReceived &amp;amp; SIGBREAKF_CTRL_C) )&lt;br /&gt;
        {&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;User break\&amp;quot; signal, ending.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
      } while( TRUE == bStillRunning );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  // Free any signals we (may have) obtained earlier&lt;br /&gt;
  if ( -1 != nSuccessSigNum    ) IExec-&amp;gt;FreeSignal(nSuccessSigNum);&lt;br /&gt;
  if ( -1 != nInProgressSigNum ) IExec-&amp;gt;FreeSignal(nInProgressSigNum);&lt;br /&gt;
  if ( -1 != nErrorSigNum      ) IExec-&amp;gt;FreeSignal(nErrorSigNum);&lt;br /&gt;
  // Release the MMU Interface (as needed)&lt;br /&gt;
  if ( NULL != IMMU ) IExec-&amp;gt;DropInterface((struct Interface *)IMMU);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;br /&gt;
&lt;br /&gt;
== Current fsldma.resource API release notes ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fsldma.resource 53.1 (30.9.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
- First release.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
fsldma.resource 53.2 (4.11.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
- Replaced the Busy Wait polling of the DMA Channel&lt;br /&gt;
  completion status with a fully event (interrupt)&lt;br /&gt;
  driven, multitasking task handler system.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
fsldma.resource 53.3 (22.11.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
- Reworked DMACopyMem() to properly handle normal&lt;br /&gt;
  cache-enabled virtual memory blocks using a&lt;br /&gt;
  combination of StartDMA()/EndDMA() and &amp;quot;CPU Snoop&amp;quot;&lt;br /&gt;
  mode on the DMA hardware.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
fsldma.resource 53.4 (4.12.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 - Major API rework and streamlining.&lt;br /&gt;
   Removed all other API calls save DMACopyMem().&lt;br /&gt;
   DMACopyMem() was renamed CopyMemDMA() and new&lt;br /&gt;
   TagItem based versions were added; CopyMemDMATagList()&lt;br /&gt;
   and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
   Seven new Tags were added to the API for use&lt;br /&gt;
   with the Tags version of CopyMemDMA. They enable&lt;br /&gt;
   using any combination of Virtual and Physical&lt;br /&gt;
   memory copies and support for new &amp;quot;Non-Blocking&amp;quot;&lt;br /&gt;
   transactions with user Notification via three&lt;br /&gt;
   possible signals; &amp;quot;Success&amp;quot;, &amp;quot;In Progress&amp;quot; and &amp;quot;Error.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   Several internal changes and improvements including&lt;br /&gt;
   but not limited to, streamlining internal signal&lt;br /&gt;
   handling between DMA Handler Tasks and user tasks&lt;br /&gt;
   and optimizing transactions using &amp;quot;Basic Chaining Mode.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   The DMA hardware&#039;s &amp;quot;Basic Chaining Mode&amp;quot; is now used&lt;br /&gt;
   internally to transfer larger single block sizes.&lt;br /&gt;
   Blocks greater than FSLDMA_OPTIMAL_BLKSIZE is size&lt;br /&gt;
   are transferred using &amp;quot;Basic Chaining Mode&amp;quot;, while&lt;br /&gt;
   blocks less than or equal to FSLDMA_OPTIMAL_BLKSIZE&lt;br /&gt;
   are transferred using &amp;quot;Basic Direct Mode.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   Previously, block sizes larger than FSLDMA_OPTIMAL_BLKSIZE&lt;br /&gt;
   were all transfered using a CPU driven loop of&lt;br /&gt;
   &amp;quot;Basic Direct Mode&amp;quot; transactions. This internal CPU&lt;br /&gt;
   driven loop has now been replaced by programming the&lt;br /&gt;
   hardware to perform a series of block transactions&lt;br /&gt;
   in a &amp;quot;Chain&amp;quot; as a single hardware transaction.&lt;br /&gt;
   This also enabled bringing out &amp;quot;Completed Successfully&amp;quot;,&lt;br /&gt;
   &amp;quot;In Progress&amp;quot; (a sub-block has transferred successfully)&lt;br /&gt;
   and &amp;quot;Error&amp;quot; signaling during &amp;quot;Non-Blocking&amp;quot; transactions.&lt;br /&gt;
&lt;br /&gt;
   Note:&lt;br /&gt;
     Currently only source and destination memory&lt;br /&gt;
     areas of the same type, Virtual-to-Virtual or&lt;br /&gt;
     Physical-to-Physical are supported.&lt;br /&gt;
&lt;br /&gt;
     Also, only Physical-to-Physical transactions&lt;br /&gt;
     support &amp;quot;Non-Blocking&amp;quot; transactions and User&lt;br /&gt;
     Notification signaling.&lt;br /&gt;
&lt;br /&gt;
     Future releases will remove these limitations.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10997</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10997"/>
		<updated>2019-12-09T22:18:12Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example 1: &amp;quot;Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 1, &amp;quot;Blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using Virtual memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct fslDMAIFace *IfslDMA      = NULL;&lt;br /&gt;
  uint32             lSize         = 0;&lt;br /&gt;
  CONST_APTR         pSrc          = NULL;&lt;br /&gt;
  APTR               pDest         = NULL;&lt;br /&gt;
  BOOL               bGotResources = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set the size of our test buffers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE; // About 64 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IfslDMA) &amp;amp;&amp;amp; (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest) )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMA() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Wait for the transaction to complete before continuing.&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pSrc,pDest);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMA(pSrc,pDest,lSize) )&lt;br /&gt;
    {&lt;br /&gt;
      // Success - Do something with the copied data and quit&lt;br /&gt;
      printf(&amp;quot;Returned with Success.\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Report the error&lt;br /&gt;
      printf(&amp;quot;Received an Error!\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example 2: &amp;quot;Non-Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 2, &amp;quot;Non-blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using user notifications and Physical memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct ExecBase    *ExecBase          = (*(struct ExecBase **)4);&lt;br /&gt;
  struct MMUIFace    *IMMU              = NULL;&lt;br /&gt;
  struct fslDMAIFace *IfslDMA           = NULL;&lt;br /&gt;
  uint32             lSize              = 0;&lt;br /&gt;
  CONST_APTR         pSrc               = NULL;&lt;br /&gt;
  APTR               pDest              = NULL;&lt;br /&gt;
  CONST_APTR         pPhySrcAttr        = NULL;&lt;br /&gt;
  APTR               pPhyDstAttr        = NULL;&lt;br /&gt;
  int8               nSuccessSigNum     = -1;&lt;br /&gt;
  int8               nInProgressSigNum  = -1;&lt;br /&gt;
  int8               nErrorSigNum       = -1;&lt;br /&gt;
  uint32             lSuccessSigMask    = 0;&lt;br /&gt;
  uint32             lInProgressSigMask = 0;&lt;br /&gt;
  uint32             lErrorSigMask      = 0;&lt;br /&gt;
  uint32             lAllSigsMask       = 0;&lt;br /&gt;
  BOOL               bGotResources      = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the MMU Interface&lt;br /&gt;
  IMMU = (struct MMUIFace *)IExec-&amp;gt;GetInterface((struct Library *)ExecBase,&lt;br /&gt;
                                                &amp;quot;MMU&amp;quot;,1,NULL);&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set our test buffer size large enough to generate some sub-block transfers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE * 4; // About 256 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate signals to wait on&lt;br /&gt;
  nSuccessSigNum    = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nInProgressSigNum = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nErrorSigNum      = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
&lt;br /&gt;
  // Construct the signal masks we need to Wait() on later.&lt;br /&gt;
  // We are assuming these values are being built with&lt;br /&gt;
  // allocated signals here, but we will verify it before use.&lt;br /&gt;
  lSuccessSigMask    = (uint32)(1L &amp;lt;&amp;lt; nSuccessSigNum);&lt;br /&gt;
  lInProgressSigMask = (uint32)(1L &amp;lt;&amp;lt; nInProgressSigNum);&lt;br /&gt;
  lErrorSigMask      = (uint32)(1L &amp;lt;&amp;lt; nErrorSigNum);&lt;br /&gt;
  lAllSigsMask = (lSuccessSigMask | lInProgressSigMask | lErrorSigMask);&lt;br /&gt;
&lt;br /&gt;
  // Obtain the pointer to ourselves (this Task)&lt;br /&gt;
  struct Task *pThisTask = IExec-&amp;gt;FindTask(NULL);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IMMU) &amp;amp;&amp;amp; (NULL != IfslDMA) &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest)   &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pThisTask )                &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nSuccessSigNum)              &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nInProgressSigNum)           &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nErrorSigNum)                 )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // In this test we are using Physical memory areas&lt;br /&gt;
    // for both source and destination, so before we&lt;br /&gt;
    // hand the transaction to the DMA hardware, we first&lt;br /&gt;
    // need to set the flush the data cache, set the&lt;br /&gt;
    // buffers to cache-inhibited and obtain the Physical&lt;br /&gt;
    // addresses for both buffers&lt;br /&gt;
&lt;br /&gt;
    // Enter Supervisor Mode&lt;br /&gt;
    APTR pUserStack = IExec-&amp;gt;SuperState();&lt;br /&gt;
&lt;br /&gt;
    // Flush out any cache for our two buffers&lt;br /&gt;
    IExec-&amp;gt;CacheClearE((APTR)pSrc,lSize,CACRF_ClearD);&lt;br /&gt;
    IExec-&amp;gt;CacheClearE(pDest,lSize,CACRF_ClearD);&lt;br /&gt;
&lt;br /&gt;
    // Now set the memory attributes to prevent further cache operations&lt;br /&gt;
    uint32 lSrcMemAttrs = IMMU-&amp;gt;GetMemoryAttrs((APTR)pSrc,0);&lt;br /&gt;
    uint32 lDstMemAttrs = IMMU-&amp;gt;GetMemoryAttrs(pDest,0);&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs((APTR)pSrc,lSize,(lSrcMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs(pDest,lSize,(lDstMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
&lt;br /&gt;
    // Get the Physical addresses for our two buffers&lt;br /&gt;
    pPhySrcAttr = IMMU-&amp;gt;GetPhysicalAddress((APTR)pSrc);&lt;br /&gt;
    pPhyDstAttr = IMMU-&amp;gt;GetPhysicalAddress(pDest);&lt;br /&gt;
&lt;br /&gt;
    // Return to User Mode&lt;br /&gt;
    if ( NULL != pUserStack ) IExec-&amp;gt;UserState(pUserStack);&lt;br /&gt;
&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMATags() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Start off the transaction then wait on completion signals.&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Non-Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,&lt;br /&gt;
           lSize,pPhySrcAttr,pPhyDstAttr);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMATags(pPhySrcAttr,pPhyDstAttr,lSize,&lt;br /&gt;
                            FSLDMA_CM_SourceIsPhysical,          TRUE,&lt;br /&gt;
                            FSLDMA_CM_DestinationIsPhysical,     TRUE,&lt;br /&gt;
                            FSLDMA_CM_DoNotWait,                 TRUE,&lt;br /&gt;
                            FSLDMA_CM_NotifyTask,                pThisTask,&lt;br /&gt;
                            FSLDMA_CM_NotifySignalNumber,        nSuccessSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyProgessSignalNumber, nInProgressSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyErrorSignalNumber,   nErrorSigNum,&lt;br /&gt;
                            TAG_DONE) )&lt;br /&gt;
    {&lt;br /&gt;
      // If the above call sets up correctly, it returns immeditately&lt;br /&gt;
      // So do something here *while* the data is being copied...&lt;br /&gt;
      printf(&amp;quot;Doing other stuff before waiting...\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
      // Now we will Wait() for the completion signals from the DMA&lt;br /&gt;
      BOOL   bStillRunning = TRUE;&lt;br /&gt;
      uint32 lSigReceived  = 0;&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        // Wait for the DMA completion/status/error signals&lt;br /&gt;
        printf(&amp;quot;Waiting for signals...\n&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        lSigReceived = IExec-&amp;gt;Wait( lAllSigsMask | SIGBREAKF_CTRL_C );&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;In Progress&amp;quot; signal&lt;br /&gt;
        if ( lInProgressSigMask == (lSigReceived &amp;amp; lInProgressSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Do something on the &amp;quot;In Process&amp;quot; signal and continue...&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;In Progress\&amp;quot; signal...\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Success&amp;quot; signal&lt;br /&gt;
        if ( lSuccessSigMask == (lSigReceived &amp;amp; lSuccessSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Success - Do something with the copied data and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Completed Successfully\&amp;quot; signal.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Error&amp;quot; signal&lt;br /&gt;
        if ( lErrorSigMask == (lSigReceived &amp;amp; lErrorSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Report the error and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Error\&amp;quot; signal!\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Finally, check if we got a Break signal from the user&lt;br /&gt;
        // just in case we want to quit out early for some reason&lt;br /&gt;
        if ( SIGBREAKF_CTRL_C == (lSigReceived &amp;amp; SIGBREAKF_CTRL_C) )&lt;br /&gt;
        {&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;User break\&amp;quot; signal, ending.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
      } while( TRUE == bStillRunning );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  // Free any signals we (may have) obtained earlier&lt;br /&gt;
  if ( -1 != nSuccessSigNum    ) IExec-&amp;gt;FreeSignal(nSuccessSigNum);&lt;br /&gt;
  if ( -1 != nInProgressSigNum ) IExec-&amp;gt;FreeSignal(nInProgressSigNum);&lt;br /&gt;
  if ( -1 != nErrorSigNum      ) IExec-&amp;gt;FreeSignal(nErrorSigNum);&lt;br /&gt;
  // Release the MMU Interface (as needed)&lt;br /&gt;
  if ( NULL != IMMU ) IExec-&amp;gt;DropInterface((struct Interface *)IMMU);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;br /&gt;
&lt;br /&gt;
== Current fsldma.resource API release notes ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fsldma.resource 53.1 (30.9.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
- First release.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
fsldma.resource 53.2 (4.11.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
- Replaced the Busy Wait polling of the DMA Channel&lt;br /&gt;
  completion status with a fully event (interrupt)&lt;br /&gt;
  driven, multitasking task handler system.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
fsldma.resource 53.3 (22.11.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
- Reworked DMACopyMem() to properly handle normal&lt;br /&gt;
  cache-enabled virtual memory blocks using a&lt;br /&gt;
  combination of StartDMA()/EndDMA() and &amp;quot;CPU Snoop&amp;quot;&lt;br /&gt;
  mode on the DMA hardware.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
fsldma.resource 53.4 (4.12.2019) &amp;lt;jkrueger&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 - Major API rework and streamlining.&lt;br /&gt;
   Removed all other API calls save DMACopyMem().&lt;br /&gt;
   DMACopyMem() was renamed CopyMemDMA() and new&lt;br /&gt;
   TagItem based versions were added; CopyMemDMATagList()&lt;br /&gt;
   and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
   Seven new Tags were added to the API for use&lt;br /&gt;
   with the Tags version of CopyMemDMA. They enable&lt;br /&gt;
   using any combination of Virtual and Physical&lt;br /&gt;
   memory copies and support for new &amp;quot;Non-Blocking&amp;quot;&lt;br /&gt;
   transactions with user Notification via three&lt;br /&gt;
   possible signals; &amp;quot;Success&amp;quot;, &amp;quot;In Progress&amp;quot; and &amp;quot;Error.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   Several internal changes and improvements including&lt;br /&gt;
   but not limited to, streamlining internal signal&lt;br /&gt;
   handling between DMA Handler Tasks and user tasks&lt;br /&gt;
   and optimizing transactions using &amp;quot;Basic Chaining Mode.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   The DMA hardware&#039;s &amp;quot;Basic Chaining Mode&amp;quot; is now used&lt;br /&gt;
   internally to transfer larger single block sizes.&lt;br /&gt;
   Blocks greater than FSLDMA_OPTIMAL_BLKSIZE is size&lt;br /&gt;
   are transferred using &amp;quot;Basic Chaining Mode&amp;quot;, while&lt;br /&gt;
   blocks less than or equal to FSLDMA_OPTIMAL_BLKSIZE&lt;br /&gt;
   are transferred using &amp;quot;Basic Direct Mode.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   Previously, block sizes larger than FSLDMA_OPTIMAL_BLKSIZE&lt;br /&gt;
   were all transfered using a CPU driven loop of&lt;br /&gt;
   &amp;quot;Basic Direct Mode&amp;quot; transactions. This internal CPU&lt;br /&gt;
   driven loop has now been replaced by programming the&lt;br /&gt;
   hardware to perform a series of block transactions&lt;br /&gt;
   in a &amp;quot;Chain&amp;quot; as a single hardware transaction.&lt;br /&gt;
   This also enabled bringing out &amp;quot;Completed Successfully&amp;quot;,&lt;br /&gt;
   &amp;quot;In Progress&amp;quot; (a sub-block has transferred successfully)&lt;br /&gt;
   and &amp;quot;Error&amp;quot; signaling during &amp;quot;Non-Blocking&amp;quot; transactions.&lt;br /&gt;
&lt;br /&gt;
   Note:&lt;br /&gt;
     Currently only source and destination memory&lt;br /&gt;
     areas of the same type, Virtual-to-Virtual or&lt;br /&gt;
     Physical-to-Physical are supported.&lt;br /&gt;
&lt;br /&gt;
     Also, only Physical-to-Physical transactions&lt;br /&gt;
     support &amp;quot;Non-Blocking&amp;quot; transactions and User&lt;br /&gt;
     Notification signaling.&lt;br /&gt;
&lt;br /&gt;
     Future releases will remove these limitations.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10996</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10996"/>
		<updated>2019-12-09T22:05:30Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Example 2: &amp;quot;Non-Blocking&amp;quot; mode */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example 1: &amp;quot;Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 1, &amp;quot;Blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using Virtual memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct fslDMAIFace *IfslDMA      = NULL;&lt;br /&gt;
  uint32             lSize         = 0;&lt;br /&gt;
  CONST_APTR         pSrc          = NULL;&lt;br /&gt;
  APTR               pDest         = NULL;&lt;br /&gt;
  BOOL               bGotResources = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set the size of our test buffers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE; // About 64 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IfslDMA) &amp;amp;&amp;amp; (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest) )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMA() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Wait for the transaction to complete before continuing.&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pSrc,pDest);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMA(pSrc,pDest,lSize) )&lt;br /&gt;
    {&lt;br /&gt;
      // Success - Do something with the copied data and quit&lt;br /&gt;
      printf(&amp;quot;Returned with Success.\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Report the error&lt;br /&gt;
      printf(&amp;quot;Received an Error!\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example 2: &amp;quot;Non-Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 2, &amp;quot;Non-blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using user notifications and Physical memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct ExecBase    *ExecBase          = (*(struct ExecBase **)4);&lt;br /&gt;
  struct MMUIFace    *IMMU              = NULL;&lt;br /&gt;
  struct fslDMAIFace *IfslDMA           = NULL;&lt;br /&gt;
  uint32             lSize              = 0;&lt;br /&gt;
  CONST_APTR         pSrc               = NULL;&lt;br /&gt;
  APTR               pDest              = NULL;&lt;br /&gt;
  CONST_APTR         pPhySrcAttr        = NULL;&lt;br /&gt;
  APTR               pPhyDstAttr        = NULL;&lt;br /&gt;
  int8               nSuccessSigNum     = -1;&lt;br /&gt;
  int8               nInProgressSigNum  = -1;&lt;br /&gt;
  int8               nErrorSigNum       = -1;&lt;br /&gt;
  uint32             lSuccessSigMask    = 0;&lt;br /&gt;
  uint32             lInProgressSigMask = 0;&lt;br /&gt;
  uint32             lErrorSigMask      = 0;&lt;br /&gt;
  uint32             lAllSigsMask       = 0;&lt;br /&gt;
  BOOL               bGotResources      = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the MMU Interface&lt;br /&gt;
  IMMU = (struct MMUIFace *)IExec-&amp;gt;GetInterface((struct Library *)ExecBase,&lt;br /&gt;
                                                &amp;quot;MMU&amp;quot;,1,NULL);&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set our test buffer size large enough to generate some sub-block transfers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE * 4; // About 256 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate signals to wait on&lt;br /&gt;
  nSuccessSigNum    = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nInProgressSigNum = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nErrorSigNum      = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
&lt;br /&gt;
  // Construct the signal masks we need to Wait() on later.&lt;br /&gt;
  // We are assuming these values are being built with&lt;br /&gt;
  // allocated signals here, but we will verify it before use.&lt;br /&gt;
  lSuccessSigMask    = (uint32)(1L &amp;lt;&amp;lt; nSuccessSigNum);&lt;br /&gt;
  lInProgressSigMask = (uint32)(1L &amp;lt;&amp;lt; nInProgressSigNum);&lt;br /&gt;
  lErrorSigMask      = (uint32)(1L &amp;lt;&amp;lt; nErrorSigNum);&lt;br /&gt;
  lAllSigsMask = (lSuccessSigMask | lInProgressSigMask | lErrorSigMask);&lt;br /&gt;
&lt;br /&gt;
  // Obtain the pointer to ourselves (this Task)&lt;br /&gt;
  struct Task *pThisTask = IExec-&amp;gt;FindTask(NULL);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IMMU) &amp;amp;&amp;amp; (NULL != IfslDMA) &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest)   &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pThisTask )                &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nSuccessSigNum)              &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nInProgressSigNum)           &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nErrorSigNum)                 )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // In this test we are using Physical memory areas&lt;br /&gt;
    // for both source and destination, so before we&lt;br /&gt;
    // hand the transaction to the DMA hardware, we first&lt;br /&gt;
    // need to set the flush the data cache, set the&lt;br /&gt;
    // buffers to cache-inhibited and obtain the Physical&lt;br /&gt;
    // addresses for both buffers&lt;br /&gt;
&lt;br /&gt;
    // Enter Supervisor Mode&lt;br /&gt;
    APTR pUserStack = IExec-&amp;gt;SuperState();&lt;br /&gt;
&lt;br /&gt;
    // Flush out any cache for our two buffers&lt;br /&gt;
    IExec-&amp;gt;CacheClearE((APTR)pSrc,lSize,CACRF_ClearD);&lt;br /&gt;
    IExec-&amp;gt;CacheClearE(pDest,lSize,CACRF_ClearD);&lt;br /&gt;
&lt;br /&gt;
    // Now set the memory attributes to prevent further cache operations&lt;br /&gt;
    uint32 lSrcMemAttrs = IMMU-&amp;gt;GetMemoryAttrs((APTR)pSrc,0);&lt;br /&gt;
    uint32 lDstMemAttrs = IMMU-&amp;gt;GetMemoryAttrs(pDest,0);&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs((APTR)pSrc,lSize,(lSrcMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs(pDest,lSize,(lDstMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
&lt;br /&gt;
    // Get the Physical addresses for our two buffers&lt;br /&gt;
    pPhySrcAttr = IMMU-&amp;gt;GetPhysicalAddress((APTR)pSrc);&lt;br /&gt;
    pPhyDstAttr = IMMU-&amp;gt;GetPhysicalAddress(pDest);&lt;br /&gt;
&lt;br /&gt;
    // Return to User Mode&lt;br /&gt;
    if ( NULL != pUserStack ) IExec-&amp;gt;UserState(pUserStack);&lt;br /&gt;
&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMATags() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Start off the transaction then wait on completion signals.&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Non-Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,&lt;br /&gt;
           lSize,pPhySrcAttr,pPhyDstAttr);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMATags(pPhySrcAttr,pPhyDstAttr,lSize,&lt;br /&gt;
                            FSLDMA_CM_SourceIsPhysical,          TRUE,&lt;br /&gt;
                            FSLDMA_CM_DestinationIsPhysical,     TRUE,&lt;br /&gt;
                            FSLDMA_CM_DoNotWait,                 TRUE,&lt;br /&gt;
                            FSLDMA_CM_NotifyTask,                pThisTask,&lt;br /&gt;
                            FSLDMA_CM_NotifySignalNumber,        nSuccessSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyProgessSignalNumber, nInProgressSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyErrorSignalNumber,   nErrorSigNum,&lt;br /&gt;
                            TAG_DONE) )&lt;br /&gt;
    {&lt;br /&gt;
      // If the above call sets up correctly, it returns immeditately&lt;br /&gt;
      // So do something here *while* the data is being copied...&lt;br /&gt;
      printf(&amp;quot;Doing other stuff before waiting...\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
      // Now we will Wait() for the completion signals from the DMA&lt;br /&gt;
      BOOL   bStillRunning = TRUE;&lt;br /&gt;
      uint32 lSigReceived  = 0;&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        // Wait for the DMA completion/status/error signals&lt;br /&gt;
        printf(&amp;quot;Waiting for signals...\n&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        lSigReceived = IExec-&amp;gt;Wait( lAllSigsMask | SIGBREAKF_CTRL_C );&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;In Progress&amp;quot; signal&lt;br /&gt;
        if ( lInProgressSigMask == (lSigReceived &amp;amp; lInProgressSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Do something on the &amp;quot;In Process&amp;quot; signal and continue...&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;In Progress\&amp;quot; signal...\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Success&amp;quot; signal&lt;br /&gt;
        if ( lSuccessSigMask == (lSigReceived &amp;amp; lSuccessSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Success - Do something with the copied data and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Completed Successfully\&amp;quot; signal.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Error&amp;quot; signal&lt;br /&gt;
        if ( lErrorSigMask == (lSigReceived &amp;amp; lErrorSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Report the error and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Error\&amp;quot; signal!\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Finally, check if we got a Break signal from the user&lt;br /&gt;
        // just in case we want to quit out early for some reason&lt;br /&gt;
        if ( SIGBREAKF_CTRL_C == (lSigReceived &amp;amp; SIGBREAKF_CTRL_C) )&lt;br /&gt;
        {&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;User break\&amp;quot; signal, ending.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
      } while( TRUE == bStillRunning );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  // Free any signals we (may have) obtained earlier&lt;br /&gt;
  if ( -1 != nSuccessSigNum    ) IExec-&amp;gt;FreeSignal(nSuccessSigNum);&lt;br /&gt;
  if ( -1 != nInProgressSigNum ) IExec-&amp;gt;FreeSignal(nInProgressSigNum);&lt;br /&gt;
  if ( -1 != nErrorSigNum      ) IExec-&amp;gt;FreeSignal(nErrorSigNum);&lt;br /&gt;
  // Release the MMU Interface (as needed)&lt;br /&gt;
  if ( NULL != IMMU ) IExec-&amp;gt;DropInterface((struct Interface *)IMMU);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10995</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10995"/>
		<updated>2019-12-09T22:03:44Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Example 2: &amp;quot;Non-Blocking&amp;quot; mode */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example 1: &amp;quot;Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 1, &amp;quot;Blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using Virtual memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct fslDMAIFace *IfslDMA      = NULL;&lt;br /&gt;
  uint32             lSize         = 0;&lt;br /&gt;
  CONST_APTR         pSrc          = NULL;&lt;br /&gt;
  APTR               pDest         = NULL;&lt;br /&gt;
  BOOL               bGotResources = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set the size of our test buffers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE; // About 64 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IfslDMA) &amp;amp;&amp;amp; (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest) )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMA() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Wait for the transaction to complete before continuing.&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pSrc,pDest);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMA(pSrc,pDest,lSize) )&lt;br /&gt;
    {&lt;br /&gt;
      // Success - Do something with the copied data and quit&lt;br /&gt;
      printf(&amp;quot;Returned with Success.\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Report the error&lt;br /&gt;
      printf(&amp;quot;Received an Error!\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example 2: &amp;quot;Non-Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 2, &amp;quot;Non-blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using user notifications and Physical memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct ExecBase    *ExecBase          = (*(struct ExecBase **)4);&lt;br /&gt;
  struct MMUIFace    *IMMU              = NULL;&lt;br /&gt;
  struct fslDMAIFace *IfslDMA           = NULL;&lt;br /&gt;
  uint32             lSize              = 0;&lt;br /&gt;
  CONST_APTR         pSrc               = NULL;&lt;br /&gt;
  APTR               pDest              = NULL;&lt;br /&gt;
  CONST_APTR         pPhySrcAttr        = NULL;&lt;br /&gt;
  APTR               pPhyDstAttr        = NULL;&lt;br /&gt;
  int8               nSuccessSigNum     = -1;&lt;br /&gt;
  int8               nInProgressSigNum  = -1;&lt;br /&gt;
  int8               nErrorSigNum       = -1;&lt;br /&gt;
  uint32             lSuccessSigMask    = 0;&lt;br /&gt;
  uint32             lInProgressSigMask = 0;&lt;br /&gt;
  uint32             lErrorSigMask      = 0;&lt;br /&gt;
  uint32             lAllSigsMask       = 0;&lt;br /&gt;
  BOOL               bGotResources      = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the MMU Interface&lt;br /&gt;
  IMMU = (struct MMUIFace *)IExec-&amp;gt;GetInterface((struct Library *)ExecBase,&lt;br /&gt;
                                                &amp;quot;MMU&amp;quot;,1,NULL);&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set our test buffer size large enough to generate some sub-block transfers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE * 4; // About 256 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate signals to wait on&lt;br /&gt;
  nSuccessSigNum    = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nInProgressSigNum = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nErrorSigNum      = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
&lt;br /&gt;
  // Construct the signal masks we need to Wait() on later.&lt;br /&gt;
  // We are assuming these values are being built with&lt;br /&gt;
  // allocated signals here, but we will verify it before use.&lt;br /&gt;
  lSuccessSigMask    = (uint32)(1L &amp;lt;&amp;lt; nSuccessSigNum);&lt;br /&gt;
  lInProgressSigMask = (uint32)(1L &amp;lt;&amp;lt; nInProgressSigNum);&lt;br /&gt;
  lErrorSigMask      = (uint32)(1L &amp;lt;&amp;lt; nErrorSigNum);&lt;br /&gt;
  lAllSigsMask = (lSuccessSigMask | lInProgressSigMask | lErrorSigMask);&lt;br /&gt;
&lt;br /&gt;
  // Obtain the pointer to ourselves (this Task)&lt;br /&gt;
  struct Task *pThisTask = IExec-&amp;gt;FindTask(NULL);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IMMU) &amp;amp;&amp;amp; (NULL != IfslDMA) &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest)   &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pThisTask )                &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nSuccessSigNum)              &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nInProgressSigNum)           &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nErrorSigNum)                 )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // In this test we are using Physical memory areas&lt;br /&gt;
    // for both source and destination, so before we&lt;br /&gt;
    // hand the transaction to the DMA hardware, we first&lt;br /&gt;
    // need to set the flush the data cache, set the&lt;br /&gt;
    // buffers to cache-inhibited and obtain the Physical&lt;br /&gt;
    // addresses for both buffers&lt;br /&gt;
&lt;br /&gt;
    // Enter Supervisor Mode&lt;br /&gt;
    APTR pUserStack = IExec-&amp;gt;SuperState();&lt;br /&gt;
&lt;br /&gt;
    // Flush out any cache for our two buffers&lt;br /&gt;
    IExec-&amp;gt;CacheClearE((APTR)pSrc,lSize,CACRF_ClearD);&lt;br /&gt;
    IExec-&amp;gt;CacheClearE(pDest,lSize,CACRF_ClearD);&lt;br /&gt;
&lt;br /&gt;
    // Now set the memory attributes to prevent further cache operations&lt;br /&gt;
    uint32 lSrcMemAttrs = IMMU-&amp;gt;GetMemoryAttrs((APTR)pSrc,0);&lt;br /&gt;
    uint32 lDstMemAttrs = IMMU-&amp;gt;GetMemoryAttrs(pDest,0);&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs((APTR)pSrc,lSize,(lSrcMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs(pDest,lSize,(lDstMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
&lt;br /&gt;
    // Get the Physical addresses for our two buffers&lt;br /&gt;
    pPhySrcAttr = IMMU-&amp;gt;GetPhysicalAddress((APTR)pSrc);&lt;br /&gt;
    pPhyDstAttr = IMMU-&amp;gt;GetPhysicalAddress(pDest);&lt;br /&gt;
&lt;br /&gt;
    // Return to User Mode&lt;br /&gt;
    if ( NULL != pUserStack ) IExec-&amp;gt;UserState(pUserStack);&lt;br /&gt;
&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMATags() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Start off the transaction then wait on completion signals.&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Non-Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,&lt;br /&gt;
           lSize,pPhySrcAttr,pPhyDstAttr);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMATags(pPhySrcAttr,pPhyDstAttr,lSize,&lt;br /&gt;
                            FSLDMA_CM_SourceIsPhysical,          TRUE,&lt;br /&gt;
                            FSLDMA_CM_DestinationIsPhysical,     TRUE,&lt;br /&gt;
                            FSLDMA_CM_DoNotWait,                 TRUE,&lt;br /&gt;
                            FSLDMA_CM_NotifyTask,                pThisTask,&lt;br /&gt;
                            FSLDMA_CM_NotifySignalNumber,        nSuccessSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyProgessSignalNumber, nInProgressSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyErrorSignalNumber,   nErrorSigNum,&lt;br /&gt;
                            TAG_DONE) )&lt;br /&gt;
    {&lt;br /&gt;
      // If the above call sets up correctly, it returns immeditately&lt;br /&gt;
      // So do something here *while* the data is being copied...&lt;br /&gt;
      printf(&amp;quot;Doing other stuff before waiting...\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
      // Now we will Wait() for the completion signals from the DMA&lt;br /&gt;
      BOOL   bStillRunning = TRUE;&lt;br /&gt;
      uint32 lSigReceived  = 0;&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        // Wait for the DMA completion/status/error signals&lt;br /&gt;
        printf(&amp;quot;Waiting for signals...\n&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        lSigReceived = IExec-&amp;gt;Wait( lAllSigsMask | SIGBREAKF_CTRL_C );&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;In Progress&amp;quot; signal&lt;br /&gt;
        if ( lInProgressSigMask == (lSigReceived &amp;amp; lInProgressSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Do something on the &amp;quot;In Process&amp;quot; signal and continue...&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;In Progress\&amp;quot; signal...\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Success&amp;quot; signal&lt;br /&gt;
        if ( lSuccessSigMask == (lSigReceived &amp;amp; lSuccessSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Success - Do something with the copied data and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Completed Successfully\&amp;quot; signal.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Error&amp;quot; signal&lt;br /&gt;
        if ( lErrorSigMask == (lSigReceived &amp;amp; lErrorSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Report the error and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Error\&amp;quot; signal!\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Finally, check if we got a Break signal from the user&lt;br /&gt;
        // just in case we want to quit out early for some reason&lt;br /&gt;
        if ( SIGBREAKF_CTRL_C == (lSigReceived &amp;amp; SIGBREAKF_CTRL_C) )&lt;br /&gt;
        {&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;User break\&amp;quot; signal, ending.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
      } while( TRUE == bStillRunning );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  // Free any signals we (may have) obtained earlier&lt;br /&gt;
  if ( -1 != nSuccessSigNum    ) IExec-&amp;gt;FreeSignal(nSuccessSigNum);&lt;br /&gt;
  if ( -1 != nInProgressSigNum ) IExec-&amp;gt;FreeSignal(nInProgressSigNum);&lt;br /&gt;
  if ( -1 != nErrorSigNum      ) IExec-&amp;gt;FreeSignal(nErrorSigNum);&lt;br /&gt;
  // Release the MMU Interface (as needed)&lt;br /&gt;
  if ( NULL != IMMU ) IExec-&amp;gt;DropInterface((struct Interface *)IMMU);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. This can be accomplished by using the IExec-&amp;gt;AllocVecTags() function together with a couple of MMU functions. Together they allow you to ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10994</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10994"/>
		<updated>2019-12-09T22:00:18Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Example 1: &amp;quot;Blocking&amp;quot; mode */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example 1: &amp;quot;Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 1, &amp;quot;Blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using Virtual memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct fslDMAIFace *IfslDMA      = NULL;&lt;br /&gt;
  uint32             lSize         = 0;&lt;br /&gt;
  CONST_APTR         pSrc          = NULL;&lt;br /&gt;
  APTR               pDest         = NULL;&lt;br /&gt;
  BOOL               bGotResources = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set the size of our test buffers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE; // About 64 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IfslDMA) &amp;amp;&amp;amp; (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest) )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMA() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Wait for the transaction to complete before continuing.&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pSrc,pDest);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMA(pSrc,pDest,lSize) )&lt;br /&gt;
    {&lt;br /&gt;
      // Success - Do something with the copied data and quit&lt;br /&gt;
      printf(&amp;quot;Returned with Success.\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Report the error&lt;br /&gt;
      printf(&amp;quot;Received an Error!\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example 2: &amp;quot;Non-Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 2, &amp;quot;Non-blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using user notifications and Physical memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct ExecBase    *ExecBase          = (*(struct ExecBase **)4);&lt;br /&gt;
  struct MMUIFace    *IMMU              = NULL;&lt;br /&gt;
  struct fslDMAIFace *IfslDMA           = NULL;&lt;br /&gt;
  uint32             lSize              = 0;&lt;br /&gt;
  CONST_APTR         pSrc               = NULL;&lt;br /&gt;
  APTR               pDest              = NULL;&lt;br /&gt;
  CONST_APTR         pPhySrcAttr        = NULL;&lt;br /&gt;
  APTR               pPhyDstAttr        = NULL;&lt;br /&gt;
  int8               nSuccessSigNum     = -1;&lt;br /&gt;
  int8               nInProgressSigNum  = -1;&lt;br /&gt;
  int8               nErrorSigNum       = -1;&lt;br /&gt;
  uint32             lSuccessSigMask    = 0;&lt;br /&gt;
  uint32             lInProgressSigMask = 0;&lt;br /&gt;
  uint32             lErrorSigMask      = 0;&lt;br /&gt;
  uint32             lAllSigsMask       = 0;&lt;br /&gt;
  BOOL               bGotResources      = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the MMU Interface&lt;br /&gt;
  IMMU = (struct MMUIFace *)IExec-&amp;gt;GetInterface((struct Library *)ExecBase,&lt;br /&gt;
                                                &amp;quot;MMU&amp;quot;,1,NULL);&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set our test buffer size large enough to generate some sub-block transfers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE * 4; // About 256 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate signals to wait on&lt;br /&gt;
  nSuccessSigNum    = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nInProgressSigNum = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nErrorSigNum      = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
&lt;br /&gt;
  // Construct the signal masks we need to Wait() on later.&lt;br /&gt;
  // We are assuming these values are being built with&lt;br /&gt;
  // allocated signals here, but we will verify it before use.&lt;br /&gt;
  lSuccessSigMask    = (uint32)(1L &amp;lt;&amp;lt; nSuccessSigNum);&lt;br /&gt;
  lInProgressSigMask = (uint32)(1L &amp;lt;&amp;lt; nInProgressSigNum);&lt;br /&gt;
  lErrorSigMask      = (uint32)(1L &amp;lt;&amp;lt; nErrorSigNum);&lt;br /&gt;
  lAllSigsMask = (lSuccessSigMask | lInProgressSigMask | lErrorSigMask);&lt;br /&gt;
&lt;br /&gt;
  // Obtain the pointer to ourselves (this Task)&lt;br /&gt;
  struct Task *pThisTask = IExec-&amp;gt;FindTask(NULL);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IMMU) &amp;amp;&amp;amp; (NULL != IfslDMA) &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest)   &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pThisTask )                &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nSuccessSigNum)              &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nInProgressSigNum)           &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nErrorSigNum)                 )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // In this test we are using Physical memory areas&lt;br /&gt;
    // for both source and destination, so before we&lt;br /&gt;
    // hand the transaction to the DMA hardware, we first&lt;br /&gt;
    // need to set the flush the data cache, set the&lt;br /&gt;
    // buffers to cache-inhibited and obtain the Physical&lt;br /&gt;
    // addresses for both buffers&lt;br /&gt;
&lt;br /&gt;
    // Enter Supervisor Mode&lt;br /&gt;
    APTR pUserStack = IExec-&amp;gt;SuperState();&lt;br /&gt;
&lt;br /&gt;
    // Flush out any cache for our two buffers&lt;br /&gt;
    IExec-&amp;gt;CacheClearE((APTR)pSrc,lSize,CACRF_ClearD);&lt;br /&gt;
    IExec-&amp;gt;CacheClearE(pDest,lSize,CACRF_ClearD);&lt;br /&gt;
&lt;br /&gt;
    // Now set the memory attributes to prevent further cache operations&lt;br /&gt;
    uint32 lSrcMemAttrs = IMMU-&amp;gt;GetMemoryAttrs((APTR)pSrc,0);&lt;br /&gt;
    uint32 lDstMemAttrs = IMMU-&amp;gt;GetMemoryAttrs(pDest,0);&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs((APTR)pSrc,lSize,(lSrcMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs(pDest,lSize,(lDstMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
&lt;br /&gt;
    // Get the Physical addresses for our two buffers&lt;br /&gt;
    pPhySrcAttr = IMMU-&amp;gt;GetPhysicalAddress((APTR)pSrc);&lt;br /&gt;
    pPhyDstAttr = IMMU-&amp;gt;GetPhysicalAddress(pDest);&lt;br /&gt;
&lt;br /&gt;
    // Return to User Mode&lt;br /&gt;
    if ( NULL != pUserStack ) IExec-&amp;gt;UserState(pUserStack);&lt;br /&gt;
&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMATags() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Start off the transaction then wait on completion signals.&lt;br /&gt;
&lt;br /&gt;
    // We use full 64-Bit values to pass in the source and destination to&lt;br /&gt;
    // IfslDMA-&amp;gt;CopyMemDMATags() so we need to use a &amp;quot;double cast&amp;quot; on the&lt;br /&gt;
    // 32-Bit pointers returned by AllocVecTags() in order to properly pass&lt;br /&gt;
    // in fully extended 64-Bit pointers.&lt;br /&gt;
    // (see &amp;lt;resource/fsldma.h&amp;gt; for more details)&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Non-Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pPhySrcAttr,pPhyDstAttr);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMATags((CONST_DMAPTR)(uint32)pPhySrcAttr,&lt;br /&gt;
                            (DMAPTR)(uint32)pPhyDstAttr,&lt;br /&gt;
                            lSize,&lt;br /&gt;
                            FSLDMA_CM_SourceIsPhysical,          TRUE,&lt;br /&gt;
                            FSLDMA_CM_DestinationIsPhysical,     TRUE,&lt;br /&gt;
                            FSLDMA_CM_DoNotWait,                 TRUE,&lt;br /&gt;
                            FSLDMA_CM_NotifyTask,                pThisTask,&lt;br /&gt;
                            FSLDMA_CM_NotifySignalNumber,        nSuccessSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyProgessSignalNumber, nInProgressSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyErrorSignalNumber,   nErrorSigNum,&lt;br /&gt;
                            TAG_DONE) )&lt;br /&gt;
    {&lt;br /&gt;
      // If the above call sets up correctly, it returns immeditately&lt;br /&gt;
      // So do something here *while* the data is being copied...&lt;br /&gt;
      printf(&amp;quot;Doing other stuff before waiting...\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
      // Now we will Wait() for the completion signals from the DMA&lt;br /&gt;
      BOOL   bStillRunning = TRUE;&lt;br /&gt;
      uint32 lSigReceived  = 0;&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        // Wait for the DMA completion/status/error signals&lt;br /&gt;
        printf(&amp;quot;Waiting for signals...\n&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        lSigReceived = IExec-&amp;gt;Wait( lAllSigsMask | SIGBREAKF_CTRL_C );&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;In Progress&amp;quot; signal&lt;br /&gt;
        if ( lInProgressSigMask == (lSigReceived &amp;amp; lInProgressSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Do something on the &amp;quot;In Process&amp;quot; signal and continue...&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;In Progress\&amp;quot; signal...\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Success&amp;quot; signal&lt;br /&gt;
        if ( lSuccessSigMask == (lSigReceived &amp;amp; lSuccessSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Success - Do something with the copied data and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Completed Successfully\&amp;quot; signal.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Error&amp;quot; signal&lt;br /&gt;
        if ( lErrorSigMask == (lSigReceived &amp;amp; lErrorSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Report the error and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Error\&amp;quot; signal!\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Finally, check if we got a Break signal from the user&lt;br /&gt;
        // just in case we want to quit out early for some reason&lt;br /&gt;
        if ( SIGBREAKF_CTRL_C == (lSigReceived &amp;amp; SIGBREAKF_CTRL_C) )&lt;br /&gt;
        {&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;User break\&amp;quot; signal, ending.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
      } while( TRUE == bStillRunning );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  // Free any signals we (may have) obtained earlier&lt;br /&gt;
  if ( -1 != nSuccessSigNum    ) IExec-&amp;gt;FreeSignal(nSuccessSigNum);&lt;br /&gt;
  if ( -1 != nInProgressSigNum ) IExec-&amp;gt;FreeSignal(nInProgressSigNum);&lt;br /&gt;
  if ( -1 != nErrorSigNum      ) IExec-&amp;gt;FreeSignal(nErrorSigNum);&lt;br /&gt;
  // Release the MMU Interface (as needed)&lt;br /&gt;
  if ( NULL != IMMU ) IExec-&amp;gt;DropInterface((struct Interface *)IMMU);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. This can be accomplished by using the IExec-&amp;gt;AllocVecTags() function together with a couple of MMU functions. Together they allow you to ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10993</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10993"/>
		<updated>2019-12-09T21:56:34Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Copy Memory Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example 1: &amp;quot;Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 1, &amp;quot;Blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using Virtual memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct fslDMAIFace *IfslDMA      = NULL;&lt;br /&gt;
  uint32             lSize         = 0;&lt;br /&gt;
  CONST_APTR         pSrc          = NULL;&lt;br /&gt;
  APTR               pDest         = NULL;&lt;br /&gt;
  BOOL               bGotResources = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set the size of our test buffers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE; // About 64 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IfslDMA) &amp;amp;&amp;amp; (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest) )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMA() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Wait for the transaction to complete before continuing.&lt;br /&gt;
&lt;br /&gt;
    // We use full 64-Bit values to pass in the source and destination to&lt;br /&gt;
    // IfslDMA-&amp;gt;CopyMemDMA() so we need to use a &amp;quot;double cast&amp;quot; on the&lt;br /&gt;
    // 32-Bit pointers returned by AllocVecTags() in order to properly pass&lt;br /&gt;
    // in fully extended 64-Bit pointers.&lt;br /&gt;
    // (see &amp;lt;resource/fsldma.h&amp;gt; for more details)&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pSrc,pDest);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMA((CONST_DMAPTR)(uint32)pSrc,&lt;br /&gt;
                                     (DMAPTR)(uint32)pDest,&lt;br /&gt;
                                     lSize) )&lt;br /&gt;
    {&lt;br /&gt;
      // Success - Do something with the copied data and quit&lt;br /&gt;
      printf(&amp;quot;Returned with Success.\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Report the error&lt;br /&gt;
      printf(&amp;quot;Received an Error!\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example 2: &amp;quot;Non-Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 2, &amp;quot;Non-blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using user notifications and Physical memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct ExecBase    *ExecBase          = (*(struct ExecBase **)4);&lt;br /&gt;
  struct MMUIFace    *IMMU              = NULL;&lt;br /&gt;
  struct fslDMAIFace *IfslDMA           = NULL;&lt;br /&gt;
  uint32             lSize              = 0;&lt;br /&gt;
  CONST_APTR         pSrc               = NULL;&lt;br /&gt;
  APTR               pDest              = NULL;&lt;br /&gt;
  CONST_APTR         pPhySrcAttr        = NULL;&lt;br /&gt;
  APTR               pPhyDstAttr        = NULL;&lt;br /&gt;
  int8               nSuccessSigNum     = -1;&lt;br /&gt;
  int8               nInProgressSigNum  = -1;&lt;br /&gt;
  int8               nErrorSigNum       = -1;&lt;br /&gt;
  uint32             lSuccessSigMask    = 0;&lt;br /&gt;
  uint32             lInProgressSigMask = 0;&lt;br /&gt;
  uint32             lErrorSigMask      = 0;&lt;br /&gt;
  uint32             lAllSigsMask       = 0;&lt;br /&gt;
  BOOL               bGotResources      = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the MMU Interface&lt;br /&gt;
  IMMU = (struct MMUIFace *)IExec-&amp;gt;GetInterface((struct Library *)ExecBase,&lt;br /&gt;
                                                &amp;quot;MMU&amp;quot;,1,NULL);&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set our test buffer size large enough to generate some sub-block transfers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE * 4; // About 256 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate signals to wait on&lt;br /&gt;
  nSuccessSigNum    = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nInProgressSigNum = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nErrorSigNum      = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
&lt;br /&gt;
  // Construct the signal masks we need to Wait() on later.&lt;br /&gt;
  // We are assuming these values are being built with&lt;br /&gt;
  // allocated signals here, but we will verify it before use.&lt;br /&gt;
  lSuccessSigMask    = (uint32)(1L &amp;lt;&amp;lt; nSuccessSigNum);&lt;br /&gt;
  lInProgressSigMask = (uint32)(1L &amp;lt;&amp;lt; nInProgressSigNum);&lt;br /&gt;
  lErrorSigMask      = (uint32)(1L &amp;lt;&amp;lt; nErrorSigNum);&lt;br /&gt;
  lAllSigsMask = (lSuccessSigMask | lInProgressSigMask | lErrorSigMask);&lt;br /&gt;
&lt;br /&gt;
  // Obtain the pointer to ourselves (this Task)&lt;br /&gt;
  struct Task *pThisTask = IExec-&amp;gt;FindTask(NULL);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IMMU) &amp;amp;&amp;amp; (NULL != IfslDMA) &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest)   &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pThisTask )                &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nSuccessSigNum)              &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nInProgressSigNum)           &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nErrorSigNum)                 )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // In this test we are using Physical memory areas&lt;br /&gt;
    // for both source and destination, so before we&lt;br /&gt;
    // hand the transaction to the DMA hardware, we first&lt;br /&gt;
    // need to set the flush the data cache, set the&lt;br /&gt;
    // buffers to cache-inhibited and obtain the Physical&lt;br /&gt;
    // addresses for both buffers&lt;br /&gt;
&lt;br /&gt;
    // Enter Supervisor Mode&lt;br /&gt;
    APTR pUserStack = IExec-&amp;gt;SuperState();&lt;br /&gt;
&lt;br /&gt;
    // Flush out any cache for our two buffers&lt;br /&gt;
    IExec-&amp;gt;CacheClearE((APTR)pSrc,lSize,CACRF_ClearD);&lt;br /&gt;
    IExec-&amp;gt;CacheClearE(pDest,lSize,CACRF_ClearD);&lt;br /&gt;
&lt;br /&gt;
    // Now set the memory attributes to prevent further cache operations&lt;br /&gt;
    uint32 lSrcMemAttrs = IMMU-&amp;gt;GetMemoryAttrs((APTR)pSrc,0);&lt;br /&gt;
    uint32 lDstMemAttrs = IMMU-&amp;gt;GetMemoryAttrs(pDest,0);&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs((APTR)pSrc,lSize,(lSrcMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs(pDest,lSize,(lDstMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
&lt;br /&gt;
    // Get the Physical addresses for our two buffers&lt;br /&gt;
    pPhySrcAttr = IMMU-&amp;gt;GetPhysicalAddress((APTR)pSrc);&lt;br /&gt;
    pPhyDstAttr = IMMU-&amp;gt;GetPhysicalAddress(pDest);&lt;br /&gt;
&lt;br /&gt;
    // Return to User Mode&lt;br /&gt;
    if ( NULL != pUserStack ) IExec-&amp;gt;UserState(pUserStack);&lt;br /&gt;
&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMATags() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Start off the transaction then wait on completion signals.&lt;br /&gt;
&lt;br /&gt;
    // We use full 64-Bit values to pass in the source and destination to&lt;br /&gt;
    // IfslDMA-&amp;gt;CopyMemDMATags() so we need to use a &amp;quot;double cast&amp;quot; on the&lt;br /&gt;
    // 32-Bit pointers returned by AllocVecTags() in order to properly pass&lt;br /&gt;
    // in fully extended 64-Bit pointers.&lt;br /&gt;
    // (see &amp;lt;resource/fsldma.h&amp;gt; for more details)&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Non-Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pPhySrcAttr,pPhyDstAttr);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMATags((CONST_DMAPTR)(uint32)pPhySrcAttr,&lt;br /&gt;
                            (DMAPTR)(uint32)pPhyDstAttr,&lt;br /&gt;
                            lSize,&lt;br /&gt;
                            FSLDMA_CM_SourceIsPhysical,          TRUE,&lt;br /&gt;
                            FSLDMA_CM_DestinationIsPhysical,     TRUE,&lt;br /&gt;
                            FSLDMA_CM_DoNotWait,                 TRUE,&lt;br /&gt;
                            FSLDMA_CM_NotifyTask,                pThisTask,&lt;br /&gt;
                            FSLDMA_CM_NotifySignalNumber,        nSuccessSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyProgessSignalNumber, nInProgressSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyErrorSignalNumber,   nErrorSigNum,&lt;br /&gt;
                            TAG_DONE) )&lt;br /&gt;
    {&lt;br /&gt;
      // If the above call sets up correctly, it returns immeditately&lt;br /&gt;
      // So do something here *while* the data is being copied...&lt;br /&gt;
      printf(&amp;quot;Doing other stuff before waiting...\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
      // Now we will Wait() for the completion signals from the DMA&lt;br /&gt;
      BOOL   bStillRunning = TRUE;&lt;br /&gt;
      uint32 lSigReceived  = 0;&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        // Wait for the DMA completion/status/error signals&lt;br /&gt;
        printf(&amp;quot;Waiting for signals...\n&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        lSigReceived = IExec-&amp;gt;Wait( lAllSigsMask | SIGBREAKF_CTRL_C );&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;In Progress&amp;quot; signal&lt;br /&gt;
        if ( lInProgressSigMask == (lSigReceived &amp;amp; lInProgressSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Do something on the &amp;quot;In Process&amp;quot; signal and continue...&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;In Progress\&amp;quot; signal...\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Success&amp;quot; signal&lt;br /&gt;
        if ( lSuccessSigMask == (lSigReceived &amp;amp; lSuccessSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Success - Do something with the copied data and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Completed Successfully\&amp;quot; signal.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Error&amp;quot; signal&lt;br /&gt;
        if ( lErrorSigMask == (lSigReceived &amp;amp; lErrorSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Report the error and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Error\&amp;quot; signal!\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Finally, check if we got a Break signal from the user&lt;br /&gt;
        // just in case we want to quit out early for some reason&lt;br /&gt;
        if ( SIGBREAKF_CTRL_C == (lSigReceived &amp;amp; SIGBREAKF_CTRL_C) )&lt;br /&gt;
        {&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;User break\&amp;quot; signal, ending.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
      } while( TRUE == bStillRunning );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  // Free any signals we (may have) obtained earlier&lt;br /&gt;
  if ( -1 != nSuccessSigNum    ) IExec-&amp;gt;FreeSignal(nSuccessSigNum);&lt;br /&gt;
  if ( -1 != nInProgressSigNum ) IExec-&amp;gt;FreeSignal(nInProgressSigNum);&lt;br /&gt;
  if ( -1 != nErrorSigNum      ) IExec-&amp;gt;FreeSignal(nErrorSigNum);&lt;br /&gt;
  // Release the MMU Interface (as needed)&lt;br /&gt;
  if ( NULL != IMMU ) IExec-&amp;gt;DropInterface((struct Interface *)IMMU);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. This can be accomplished by using the IExec-&amp;gt;AllocVecTags() function together with a couple of MMU functions. Together they allow you to ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10985</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10985"/>
		<updated>2019-12-04T23:37:38Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Example 1: &amp;quot;Blocking&amp;quot; mode */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example 1: &amp;quot;Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 1, &amp;quot;Blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using Virtual memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct fslDMAIFace *IfslDMA      = NULL;&lt;br /&gt;
  uint32             lSize         = 0;&lt;br /&gt;
  CONST_APTR         pSrc          = NULL;&lt;br /&gt;
  APTR               pDest         = NULL;&lt;br /&gt;
  BOOL               bGotResources = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set the size of our test buffers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE; // About 64 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IfslDMA) &amp;amp;&amp;amp; (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest) )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMA() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Wait for the transaction to complete before continuing.&lt;br /&gt;
&lt;br /&gt;
    // We use full 64-Bit values to pass in the source and destination to&lt;br /&gt;
    // IfslDMA-&amp;gt;CopyMemDMA() so we need to use a &amp;quot;double cast&amp;quot; on the&lt;br /&gt;
    // 32-Bit pointers returned by AllocVecTags() in order to properly pass&lt;br /&gt;
    // in fully extended 64-Bit pointers.&lt;br /&gt;
    // (see &amp;lt;resource/fsldma.h&amp;gt; for more details)&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pSrc,pDest);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMA((CONST_DMAPTR)(uint32)pSrc,&lt;br /&gt;
                                     (DMAPTR)(uint32)pDest,&lt;br /&gt;
                                     lSize) )&lt;br /&gt;
    {&lt;br /&gt;
      // Success - Do something with the copied data and quit&lt;br /&gt;
      printf(&amp;quot;Returned with Success.\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
      // Report the error&lt;br /&gt;
      printf(&amp;quot;Received an Error!\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example 2: &amp;quot;Non-Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 2, &amp;quot;Non-blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using user notifications and Physical memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct ExecBase    *ExecBase          = (*(struct ExecBase **)4);&lt;br /&gt;
  struct MMUIFace    *IMMU              = NULL;&lt;br /&gt;
  struct fslDMAIFace *IfslDMA           = NULL;&lt;br /&gt;
  uint32             lSize              = 0;&lt;br /&gt;
  CONST_APTR         pSrc               = NULL;&lt;br /&gt;
  APTR               pDest              = NULL;&lt;br /&gt;
  CONST_APTR         pPhySrcAttr        = NULL;&lt;br /&gt;
  APTR               pPhyDstAttr        = NULL;&lt;br /&gt;
  int8               nSuccessSigNum     = -1;&lt;br /&gt;
  int8               nInProgressSigNum  = -1;&lt;br /&gt;
  int8               nErrorSigNum       = -1;&lt;br /&gt;
  uint32             lSuccessSigMask    = 0;&lt;br /&gt;
  uint32             lInProgressSigMask = 0;&lt;br /&gt;
  uint32             lErrorSigMask      = 0;&lt;br /&gt;
  uint32             lAllSigsMask       = 0;&lt;br /&gt;
  BOOL               bGotResources      = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the MMU Interface&lt;br /&gt;
  IMMU = (struct MMUIFace *)IExec-&amp;gt;GetInterface((struct Library *)ExecBase,&lt;br /&gt;
                                                &amp;quot;MMU&amp;quot;,1,NULL);&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set our test buffer size large enough to generate some sub-block transfers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE * 4; // About 256 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate signals to wait on&lt;br /&gt;
  nSuccessSigNum    = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nInProgressSigNum = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nErrorSigNum      = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
&lt;br /&gt;
  // Construct the signal masks we need to Wait() on later.&lt;br /&gt;
  // We are assuming these values are being built with&lt;br /&gt;
  // allocated signals here, but we will verify it before use.&lt;br /&gt;
  lSuccessSigMask    = (uint32)(1L &amp;lt;&amp;lt; nSuccessSigNum);&lt;br /&gt;
  lInProgressSigMask = (uint32)(1L &amp;lt;&amp;lt; nInProgressSigNum);&lt;br /&gt;
  lErrorSigMask      = (uint32)(1L &amp;lt;&amp;lt; nErrorSigNum);&lt;br /&gt;
  lAllSigsMask = (lSuccessSigMask | lInProgressSigMask | lErrorSigMask);&lt;br /&gt;
&lt;br /&gt;
  // Obtain the pointer to ourselves (this Task)&lt;br /&gt;
  struct Task *pThisTask = IExec-&amp;gt;FindTask(NULL);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IMMU) &amp;amp;&amp;amp; (NULL != IfslDMA) &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest)   &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pThisTask )                &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nSuccessSigNum)              &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nInProgressSigNum)           &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nErrorSigNum)                 )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // In this test we are using Physical memory areas&lt;br /&gt;
    // for both source and destination, so before we&lt;br /&gt;
    // hand the transaction to the DMA hardware, we first&lt;br /&gt;
    // need to set the flush the data cache, set the&lt;br /&gt;
    // buffers to cache-inhibited and obtain the Physical&lt;br /&gt;
    // addresses for both buffers&lt;br /&gt;
&lt;br /&gt;
    // Enter Supervisor Mode&lt;br /&gt;
    APTR pUserStack = IExec-&amp;gt;SuperState();&lt;br /&gt;
&lt;br /&gt;
    // Flush out any cache for our two buffers&lt;br /&gt;
    IExec-&amp;gt;CacheClearE((APTR)pSrc,lSize,CACRF_ClearD);&lt;br /&gt;
    IExec-&amp;gt;CacheClearE(pDest,lSize,CACRF_ClearD);&lt;br /&gt;
&lt;br /&gt;
    // Now set the memory attributes to prevent further cache operations&lt;br /&gt;
    uint32 lSrcMemAttrs = IMMU-&amp;gt;GetMemoryAttrs((APTR)pSrc,0);&lt;br /&gt;
    uint32 lDstMemAttrs = IMMU-&amp;gt;GetMemoryAttrs(pDest,0);&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs((APTR)pSrc,lSize,(lSrcMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs(pDest,lSize,(lDstMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
&lt;br /&gt;
    // Get the Physical addresses for our two buffers&lt;br /&gt;
    pPhySrcAttr = IMMU-&amp;gt;GetPhysicalAddress((APTR)pSrc);&lt;br /&gt;
    pPhyDstAttr = IMMU-&amp;gt;GetPhysicalAddress(pDest);&lt;br /&gt;
&lt;br /&gt;
    // Return to User Mode&lt;br /&gt;
    if ( NULL != pUserStack ) IExec-&amp;gt;UserState(pUserStack);&lt;br /&gt;
&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMATags() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Start off the transaction then wait on completion signals.&lt;br /&gt;
&lt;br /&gt;
    // We use full 64-Bit values to pass in the source and destination to&lt;br /&gt;
    // IfslDMA-&amp;gt;CopyMemDMATags() so we need to use a &amp;quot;double cast&amp;quot; on the&lt;br /&gt;
    // 32-Bit pointers returned by AllocVecTags() in order to properly pass&lt;br /&gt;
    // in fully extended 64-Bit pointers.&lt;br /&gt;
    // (see &amp;lt;resource/fsldma.h&amp;gt; for more details)&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Non-Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pPhySrcAttr,pPhyDstAttr);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMATags((CONST_DMAPTR)(uint32)pPhySrcAttr,&lt;br /&gt;
                            (DMAPTR)(uint32)pPhyDstAttr,&lt;br /&gt;
                            lSize,&lt;br /&gt;
                            FSLDMA_CM_SourceIsPhysical,          TRUE,&lt;br /&gt;
                            FSLDMA_CM_DestinationIsPhysical,     TRUE,&lt;br /&gt;
                            FSLDMA_CM_DoNotWait,                 TRUE,&lt;br /&gt;
                            FSLDMA_CM_NotifyTask,                pThisTask,&lt;br /&gt;
                            FSLDMA_CM_NotifySignalNumber,        nSuccessSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyProgessSignalNumber, nInProgressSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyErrorSignalNumber,   nErrorSigNum,&lt;br /&gt;
                            TAG_DONE) )&lt;br /&gt;
    {&lt;br /&gt;
      // If the above call sets up correctly, it returns immeditately&lt;br /&gt;
      // So do something here *while* the data is being copied...&lt;br /&gt;
      printf(&amp;quot;Doing other stuff before waiting...\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
      // Now we will Wait() for the completion signals from the DMA&lt;br /&gt;
      BOOL   bStillRunning = TRUE;&lt;br /&gt;
      uint32 lSigReceived  = 0;&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        // Wait for the DMA completion/status/error signals&lt;br /&gt;
        printf(&amp;quot;Waiting for signals...\n&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        lSigReceived = IExec-&amp;gt;Wait( lAllSigsMask | SIGBREAKF_CTRL_C );&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;In Progress&amp;quot; signal&lt;br /&gt;
        if ( lInProgressSigMask == (lSigReceived &amp;amp; lInProgressSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Do something on the &amp;quot;In Process&amp;quot; signal and continue...&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;In Progress\&amp;quot; signal...\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Success&amp;quot; signal&lt;br /&gt;
        if ( lSuccessSigMask == (lSigReceived &amp;amp; lSuccessSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Success - Do something with the copied data and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Completed Successfully\&amp;quot; signal.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Error&amp;quot; signal&lt;br /&gt;
        if ( lErrorSigMask == (lSigReceived &amp;amp; lErrorSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Report the error and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Error\&amp;quot; signal!\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Finally, check if we got a Break signal from the user&lt;br /&gt;
        // just in case we want to quit out early for some reason&lt;br /&gt;
        if ( SIGBREAKF_CTRL_C == (lSigReceived &amp;amp; SIGBREAKF_CTRL_C) )&lt;br /&gt;
        {&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;User break\&amp;quot; signal, ending.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
      } while( TRUE == bStillRunning );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  // Free any signals we (may have) obtained earlier&lt;br /&gt;
  if ( -1 != nSuccessSigNum    ) IExec-&amp;gt;FreeSignal(nSuccessSigNum);&lt;br /&gt;
  if ( -1 != nInProgressSigNum ) IExec-&amp;gt;FreeSignal(nInProgressSigNum);&lt;br /&gt;
  if ( -1 != nErrorSigNum      ) IExec-&amp;gt;FreeSignal(nErrorSigNum);&lt;br /&gt;
  // Release the MMU Interface (as needed)&lt;br /&gt;
  if ( NULL != IMMU ) IExec-&amp;gt;DropInterface((struct Interface *)IMMU);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. This can be accomplished by using the IExec-&amp;gt;AllocVecTags() function together with a couple of MMU functions. Together they allow you to ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10984</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10984"/>
		<updated>2019-12-04T23:27:44Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* fsldma.resource */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example 1: &amp;quot;Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
# &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  // Allocate a couple of test buffers (fill the source with data)&lt;br /&gt;
  uint32     lSize = FSLDMA_OPTIMAL_BLKSIZE;&lt;br /&gt;
  CONST_APTR pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                                         AVT_Type,           MEMF_SHARED,&lt;br /&gt;
                                         AVT_ClearWithValue, 0xB3,&lt;br /&gt;
                                         TAG_DONE);&lt;br /&gt;
  APTR       pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                                         AVT_Type,           MEMF_SHARED,&lt;br /&gt;
                                         AVT_ClearWithValue, 0,&lt;br /&gt;
                                         TAG_DONE);&lt;br /&gt;
  if ( (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest) )&lt;br /&gt;
  {&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMA() to perform the memory copy using the DMA hardware.&lt;br /&gt;
    // We use full 64-Bit values to pass in the source and destination to CopyMemDMA&lt;br /&gt;
    // so we need to use a &amp;quot;double cast&amp;quot; on the 32-Bit pointers returned by&lt;br /&gt;
    // AllocVecTags() in order to properly pass in fully extended 64-Bit pointers&lt;br /&gt;
    // (see &amp;lt;resource/fsldma.h&amp;gt; for more details)&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMA((CONST_DMAPTR)(uint32)pSrc,&lt;br /&gt;
                                     (DMAPTR)(uint32)pDest,&lt;br /&gt;
                                     lSize) )&lt;br /&gt;
    {&lt;br /&gt;
      // Success - Do something with the copied data&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Free our test buffers&lt;br /&gt;
    IExec-&amp;gt;FreeVec(pSrc);&lt;br /&gt;
    IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example 2: &amp;quot;Non-Blocking&amp;quot; mode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;amiga_compiler.h&amp;gt;&lt;br /&gt;
#include &amp;lt;exec/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dos/dos.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// fsldma.resource Example 2, &amp;quot;Non-blocking&amp;quot; DMA Copy&lt;br /&gt;
// test using user notifications and Physical memory areas&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  struct ExecBase    *ExecBase          = (*(struct ExecBase **)4);&lt;br /&gt;
  struct MMUIFace    *IMMU              = NULL;&lt;br /&gt;
  struct fslDMAIFace *IfslDMA           = NULL;&lt;br /&gt;
  uint32             lSize              = 0;&lt;br /&gt;
  CONST_APTR         pSrc               = NULL;&lt;br /&gt;
  APTR               pDest              = NULL;&lt;br /&gt;
  CONST_APTR         pPhySrcAttr        = NULL;&lt;br /&gt;
  APTR               pPhyDstAttr        = NULL;&lt;br /&gt;
  int8               nSuccessSigNum     = -1;&lt;br /&gt;
  int8               nInProgressSigNum  = -1;&lt;br /&gt;
  int8               nErrorSigNum       = -1;&lt;br /&gt;
  uint32             lSuccessSigMask    = 0;&lt;br /&gt;
  uint32             lInProgressSigMask = 0;&lt;br /&gt;
  uint32             lErrorSigMask      = 0;&lt;br /&gt;
  uint32             lAllSigsMask       = 0;&lt;br /&gt;
  BOOL               bGotResources      = FALSE;&lt;br /&gt;
&lt;br /&gt;
  // Obtain the MMU Interface&lt;br /&gt;
  IMMU = (struct MMUIFace *)IExec-&amp;gt;GetInterface((struct Library *)ExecBase,&lt;br /&gt;
                                                &amp;quot;MMU&amp;quot;,1,NULL);&lt;br /&gt;
  // Obtain the fsldma.resource&lt;br /&gt;
  IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&lt;br /&gt;
  // Set our test buffer size large enough to generate some sub-block transfers&lt;br /&gt;
  lSize = FSLDMA_OPTIMAL_BLKSIZE * 4; // About 256 MB&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test source buffer (fill with some data)&lt;br /&gt;
  pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0xB3,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate a test destination buffer (clear with zeroes)&lt;br /&gt;
  pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                              AVT_Type,              MEMF_SHARED,&lt;br /&gt;
                              AVT_Contiguous,        TRUE,&lt;br /&gt;
                              AVT_Lock,              TRUE,&lt;br /&gt;
                              AVT_Alignment,         64,&lt;br /&gt;
                              AVT_PhysicalAlignment, 64,&lt;br /&gt;
                              AVT_ClearWithValue,    0,&lt;br /&gt;
                              TAG_DONE);&lt;br /&gt;
&lt;br /&gt;
  // Allocate signals to wait on&lt;br /&gt;
  nSuccessSigNum    = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nInProgressSigNum = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
  nErrorSigNum      = IExec-&amp;gt;AllocSignal((int8)-1);&lt;br /&gt;
&lt;br /&gt;
  // Construct the signal masks we need to Wait() on later.&lt;br /&gt;
  // We are assuming these values are being built with&lt;br /&gt;
  // allocated signals here, but we will verify it before use.&lt;br /&gt;
  lSuccessSigMask    = (uint32)(1L &amp;lt;&amp;lt; nSuccessSigNum);&lt;br /&gt;
  lInProgressSigMask = (uint32)(1L &amp;lt;&amp;lt; nInProgressSigNum);&lt;br /&gt;
  lErrorSigMask      = (uint32)(1L &amp;lt;&amp;lt; nErrorSigNum);&lt;br /&gt;
  lAllSigsMask = (lSuccessSigMask | lInProgressSigMask | lErrorSigMask);&lt;br /&gt;
&lt;br /&gt;
  // Obtain the pointer to ourselves (this Task)&lt;br /&gt;
  struct Task *pThisTask = IExec-&amp;gt;FindTask(NULL);&lt;br /&gt;
&lt;br /&gt;
  // Verify we got all resources needed for the test&lt;br /&gt;
  if ( (NULL != IMMU) &amp;amp;&amp;amp; (NULL != IfslDMA) &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest)   &amp;amp;&amp;amp;&lt;br /&gt;
       (NULL != pThisTask )                &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nSuccessSigNum)              &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nInProgressSigNum)           &amp;amp;&amp;amp;&lt;br /&gt;
       (-1 != nErrorSigNum)                 )&lt;br /&gt;
  {&lt;br /&gt;
    bGotResources = TRUE;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ( TRUE == bGotResources )&lt;br /&gt;
  {&lt;br /&gt;
    // In this test we are using Physical memory areas&lt;br /&gt;
    // for both source and destination, so before we&lt;br /&gt;
    // hand the transaction to the DMA hardware, we first&lt;br /&gt;
    // need to set the flush the data cache, set the&lt;br /&gt;
    // buffers to cache-inhibited and obtain the Physical&lt;br /&gt;
    // addresses for both buffers&lt;br /&gt;
&lt;br /&gt;
    // Enter Supervisor Mode&lt;br /&gt;
    APTR pUserStack = IExec-&amp;gt;SuperState();&lt;br /&gt;
&lt;br /&gt;
    // Flush out any cache for our two buffers&lt;br /&gt;
    IExec-&amp;gt;CacheClearE((APTR)pSrc,lSize,CACRF_ClearD);&lt;br /&gt;
    IExec-&amp;gt;CacheClearE(pDest,lSize,CACRF_ClearD);&lt;br /&gt;
&lt;br /&gt;
    // Now set the memory attributes to prevent further cache operations&lt;br /&gt;
    uint32 lSrcMemAttrs = IMMU-&amp;gt;GetMemoryAttrs((APTR)pSrc,0);&lt;br /&gt;
    uint32 lDstMemAttrs = IMMU-&amp;gt;GetMemoryAttrs(pDest,0);&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs((APTR)pSrc,lSize,(lSrcMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
    IMMU-&amp;gt;SetMemoryAttrs(pDest,lSize,(lDstMemAttrs | FSLDMA_PHYMEM_ATTRS));&lt;br /&gt;
&lt;br /&gt;
    // Get the Physical addresses for our two buffers&lt;br /&gt;
    pPhySrcAttr = IMMU-&amp;gt;GetPhysicalAddress((APTR)pSrc);&lt;br /&gt;
    pPhyDstAttr = IMMU-&amp;gt;GetPhysicalAddress(pDest);&lt;br /&gt;
&lt;br /&gt;
    // Return to User Mode&lt;br /&gt;
    if ( NULL != pUserStack ) IExec-&amp;gt;UserState(pUserStack);&lt;br /&gt;
&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMATags() to perform the memory copy using the&lt;br /&gt;
    // DMA hardware. Start off the transaction then wait on completion signals.&lt;br /&gt;
&lt;br /&gt;
    // We use full 64-Bit values to pass in the source and destination to&lt;br /&gt;
    // IfslDMA-&amp;gt;CopyMemDMATags() so we need to use a &amp;quot;double cast&amp;quot; on the&lt;br /&gt;
    // 32-Bit pointers returned by AllocVecTags() in order to properly pass&lt;br /&gt;
    // in fully extended 64-Bit pointers.&lt;br /&gt;
    // (see &amp;lt;resource/fsldma.h&amp;gt; for more details)&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;Starting \&amp;quot;Non-Blocking\&amp;quot; DMA Transaction&amp;quot;&lt;br /&gt;
           &amp;quot; of %ld bytes from 0x%08lx to 0x%08lx...\n&amp;quot;,lSize,pPhySrcAttr,pPhyDstAttr);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMATags((CONST_DMAPTR)(uint32)pPhySrcAttr,&lt;br /&gt;
                            (DMAPTR)(uint32)pPhyDstAttr,&lt;br /&gt;
                            lSize,&lt;br /&gt;
                            FSLDMA_CM_SourceIsPhysical,          TRUE,&lt;br /&gt;
                            FSLDMA_CM_DestinationIsPhysical,     TRUE,&lt;br /&gt;
                            FSLDMA_CM_DoNotWait,                 TRUE,&lt;br /&gt;
                            FSLDMA_CM_NotifyTask,                pThisTask,&lt;br /&gt;
                            FSLDMA_CM_NotifySignalNumber,        nSuccessSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyProgessSignalNumber, nInProgressSigNum,&lt;br /&gt;
                            FSLDMA_CM_NotifyErrorSignalNumber,   nErrorSigNum,&lt;br /&gt;
                            TAG_DONE) )&lt;br /&gt;
    {&lt;br /&gt;
      // If the above call sets up correctly, it returns immeditately&lt;br /&gt;
      // So do something here *while* the data is being copied...&lt;br /&gt;
      printf(&amp;quot;Doing other stuff before waiting...\n&amp;quot;);&lt;br /&gt;
      fflush(stdout);&lt;br /&gt;
&lt;br /&gt;
      // Now we will Wait() for the completion signals from the DMA&lt;br /&gt;
      BOOL   bStillRunning = TRUE;&lt;br /&gt;
      uint32 lSigReceived  = 0;&lt;br /&gt;
      do&lt;br /&gt;
      {&lt;br /&gt;
        // Wait for the DMA completion/status/error signals&lt;br /&gt;
        printf(&amp;quot;Waiting for signals...\n&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        lSigReceived = IExec-&amp;gt;Wait( lAllSigsMask | SIGBREAKF_CTRL_C );&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;In Progress&amp;quot; signal&lt;br /&gt;
        if ( lInProgressSigMask == (lSigReceived &amp;amp; lInProgressSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Do something on the &amp;quot;In Process&amp;quot; signal and continue...&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;In Progress\&amp;quot; signal...\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Success&amp;quot; signal&lt;br /&gt;
        if ( lSuccessSigMask == (lSigReceived &amp;amp; lSuccessSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Success - Do something with the copied data and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Completed Successfully\&amp;quot; signal.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Test for the &amp;quot;Error&amp;quot; signal&lt;br /&gt;
        if ( lErrorSigMask == (lSigReceived &amp;amp; lErrorSigMask) )&lt;br /&gt;
        {&lt;br /&gt;
          // Report the error and quit&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;Error\&amp;quot; signal!\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Finally, check if we got a Break signal from the user&lt;br /&gt;
        // just in case we want to quit out early for some reason&lt;br /&gt;
        if ( SIGBREAKF_CTRL_C == (lSigReceived &amp;amp; SIGBREAKF_CTRL_C) )&lt;br /&gt;
        {&lt;br /&gt;
          printf(&amp;quot;Received an \&amp;quot;User break\&amp;quot; signal, ending.\n&amp;quot;);&lt;br /&gt;
          fflush(stdout);&lt;br /&gt;
          bStillRunning = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
      } while( TRUE == bStillRunning );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  else&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Failed to obtain resources, aborting test.\n&amp;quot;);&lt;br /&gt;
    fflush(stdout);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Free our test buffers (as needed)&lt;br /&gt;
  if ( NULL != pSrc  ) IExec-&amp;gt;FreeVec((APTR)pSrc);&lt;br /&gt;
  if ( NULL != pDest ) IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  // Free any signals we (may have) obtained earlier&lt;br /&gt;
  if ( -1 != nSuccessSigNum    ) IExec-&amp;gt;FreeSignal(nSuccessSigNum);&lt;br /&gt;
  if ( -1 != nInProgressSigNum ) IExec-&amp;gt;FreeSignal(nInProgressSigNum);&lt;br /&gt;
  if ( -1 != nErrorSigNum      ) IExec-&amp;gt;FreeSignal(nErrorSigNum);&lt;br /&gt;
  // Release the MMU Interface (as needed)&lt;br /&gt;
  if ( NULL != IMMU ) IExec-&amp;gt;DropInterface((struct Interface *)IMMU);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. This can be accomplished by using the IExec-&amp;gt;AllocVecTags() function together with a couple of MMU functions. Together they allow you to ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10983</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10983"/>
		<updated>2019-12-04T20:11:30Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Optimal use of the DMA Engine */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
# &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  // Allocate a couple of test buffers (fill the source with data)&lt;br /&gt;
  uint32     lSize = FSLDMA_OPTIMAL_BLKSIZE;&lt;br /&gt;
  CONST_APTR pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                                         AVT_Type,           MEMF_SHARED,&lt;br /&gt;
                                         AVT_ClearWithValue, 0xB3,&lt;br /&gt;
                                         TAG_DONE);&lt;br /&gt;
  APTR       pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                                         AVT_Type,           MEMF_SHARED,&lt;br /&gt;
                                         AVT_ClearWithValue, 0,&lt;br /&gt;
                                         TAG_DONE);&lt;br /&gt;
  if ( (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest) )&lt;br /&gt;
  {&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMA() to perform the memory copy using the DMA hardware.&lt;br /&gt;
    // We use full 64-Bit values to pass in the source and destination to CopyMemDMA&lt;br /&gt;
    // so we need to use a &amp;quot;double cast&amp;quot; on the 32-Bit pointers returned by&lt;br /&gt;
    // AllocVecTags() in order to properly pass in fully extended 64-Bit pointers&lt;br /&gt;
    // (see &amp;lt;resource/fsldma.h&amp;gt; for more details)&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMA((CONST_DMAPTR)(uint32)pSrc,&lt;br /&gt;
                                     (DMAPTR)(uint32)pDest,&lt;br /&gt;
                                     lSize) )&lt;br /&gt;
    {&lt;br /&gt;
      // Success - Do something with the copied data&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Free our test buffers&lt;br /&gt;
    IExec-&amp;gt;FreeVec(pSrc);&lt;br /&gt;
    IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. This can be accomplished by using the IExec-&amp;gt;AllocVecTags() function together with a couple of MMU functions. Together they allow you to ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10982</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10982"/>
		<updated>2019-12-04T20:10:44Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Example usage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
# &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  // Allocate a couple of test buffers (fill the source with data)&lt;br /&gt;
  uint32     lSize = FSLDMA_OPTIMAL_BLKSIZE;&lt;br /&gt;
  CONST_APTR pSrc  = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                                         AVT_Type,           MEMF_SHARED,&lt;br /&gt;
                                         AVT_ClearWithValue, 0xB3,&lt;br /&gt;
                                         TAG_DONE);&lt;br /&gt;
  APTR       pDest = IExec-&amp;gt;AllocVecTags(lSize,&lt;br /&gt;
                                         AVT_Type,           MEMF_SHARED,&lt;br /&gt;
                                         AVT_ClearWithValue, 0,&lt;br /&gt;
                                         TAG_DONE);&lt;br /&gt;
  if ( (NULL != pSrc) &amp;amp;&amp;amp; (NULL != pDest) )&lt;br /&gt;
  {&lt;br /&gt;
    // Call IfslDMA-&amp;gt;CopyMemDMA() to perform the memory copy using the DMA hardware.&lt;br /&gt;
    // We use full 64-Bit values to pass in the source and destination to CopyMemDMA&lt;br /&gt;
    // so we need to use a &amp;quot;double cast&amp;quot; on the 32-Bit pointers returned by&lt;br /&gt;
    // AllocVecTags() in order to properly pass in fully extended 64-Bit pointers&lt;br /&gt;
    // (see &amp;lt;resource/fsldma.h&amp;gt; for more details)&lt;br /&gt;
&lt;br /&gt;
    if ( TRUE == IfslDMA-&amp;gt;CopyMemDMA((CONST_DMAPTR)(uint32)pSrc,&lt;br /&gt;
                                     (DMAPTR)(uint32)pDest,&lt;br /&gt;
                                     lSize) )&lt;br /&gt;
    {&lt;br /&gt;
      // Success - Do something with the copied data&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Free our test buffers&lt;br /&gt;
    IExec-&amp;gt;FreeVec(pSrc);&lt;br /&gt;
    IExec-&amp;gt;FreeVec(pDest);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. This can be accomplished by using the IExec-&amp;gt;AllocVecTags() function together with a couple of MMU functions. Together they allow you to ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
Alignment requirements are one of items taken care of for you by the DMAAllocPhysicalMemory() function.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10981</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10981"/>
		<updated>2019-12-04T20:00:55Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* The FslDMA API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Author ==&lt;br /&gt;
&lt;br /&gt;
Jamie Krueger, BITbyBIT Software Group LLC&amp;lt;br/&amp;gt;&lt;br /&gt;
Copyright (c) 2019 Trevor Dickinson&amp;lt;br/&amp;gt;&lt;br /&gt;
Used by permission.&lt;br /&gt;
&lt;br /&gt;
== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource current consists of:&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Three API calls make up the FslDMA API; CopyMemDMA(), CopyMemDMATagList() and CopyMemDMATags().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL CopyMemDMA( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL CopyMemDMATags( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize, uint32 TagItem1, ... );&lt;br /&gt;
  BOOL CopyMemDMATagList( CONST_DMAPTR pSourceBuffer, DMAPTR pDestBuffer, uint32 lBufferSize, const struct TagItem *tags );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first call, CopyMemDMA(), attempts to perform a &amp;quot;blocking&amp;quot; (does not return to the user until after the requested transfer has either succeeded or failed) operation. A value of TRUE is returned upon success and FALSE if an error occurred. The CopyMemDMA() call will automatically fall back to using an internal fast CPU copy if the requested size is too small to be efficient, or an error occurred in the DMA transaction.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using any one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be sent to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
Alignment requirements are one of items taken care of for you by the DMAAllocPhysicalMemory() function.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Multitasking-Diagram.png&amp;diff=10980</id>
		<title>File:DMACopyMem-Multitasking-Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Multitasking-Diagram.png&amp;diff=10980"/>
		<updated>2019-12-04T19:47:24Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: Jamie Krueger uploaded a new version of File:DMACopyMem-Multitasking-Diagram.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;DMA Engine diagram of multiple simultaneous memory copy calls.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Diagram.png&amp;diff=10979</id>
		<title>File:DMACopyMem-Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Diagram.png&amp;diff=10979"/>
		<updated>2019-12-04T19:42:31Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: Jamie Krueger uploaded a new version of File:DMACopyMem-Diagram.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diagram of DMA Engine&#039;s Copy Memory function (execution flow)&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Diagram.png&amp;diff=10978</id>
		<title>File:DMACopyMem-Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Diagram.png&amp;diff=10978"/>
		<updated>2019-12-04T19:41:21Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: Jamie Krueger uploaded a new version of File:DMACopyMem-Diagram.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diagram of DMA Engine&#039;s Copy Memory function (execution flow)&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Diagram.png&amp;diff=10977</id>
		<title>File:DMACopyMem-Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Diagram.png&amp;diff=10977"/>
		<updated>2019-12-04T19:35:03Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: Jamie Krueger uploaded a new version of File:DMACopyMem-Diagram.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diagram of DMA Engine&#039;s Copy Memory function (execution flow)&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10973</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10973"/>
		<updated>2019-11-20T16:31:01Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Performance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222)&lt;br /&gt;
move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly&lt;br /&gt;
equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy,&lt;br /&gt;
and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle,&lt;br /&gt;
to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
Alignment requirements are one of items taken care of for you by the DMAAllocPhysicalMemory() function.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10972</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10972"/>
		<updated>2019-11-20T16:30:15Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222) move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy, and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle, to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
Alignment requirements are one of items taken care of for you by the DMAAllocPhysicalMemory() function.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10971</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10971"/>
		<updated>2019-11-20T16:29:43Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* When to use the DMA Engine */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222) move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy, and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle, to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== Optimal use of the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
To gain the best performance from the DMA Engines, block sizes of 256 bytes or more should be used.&lt;br /&gt;
Also, if possible the size should be an even multiple of at least 4 bytes.&lt;br /&gt;
&lt;br /&gt;
Additionally the memory blocks (source and destination) should be aligned to start on a 64 Byte boundary.&lt;br /&gt;
Alignment requirements are one of items taken care of for you by the DMAAllocPhysicalMemory() function.&lt;br /&gt;
&lt;br /&gt;
The DMA Engine can and does handle misaligned and odd sized data blocks by first shifting the minimum&lt;br /&gt;
required bytes to correct the alignment, then taking smaller chunks of data until the largest chunk of&lt;br /&gt;
the block can be moved. It can also handle copies of as little as one byte (don&#039;t do this).&lt;br /&gt;
&lt;br /&gt;
However, this does degrade performance.&lt;br /&gt;
&lt;br /&gt;
In general, the larger the data block the better.&lt;br /&gt;
&lt;br /&gt;
=== When not to use the DMA Engine ===&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10970</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10970"/>
		<updated>2019-11-18T18:56:49Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Testing DMA memory copies vs their CPU based equivalent indicates that the DMA hardware on all three models (X5000/20, X5000/40 and A1222) move data approximately two to three times faster than the CPU does so alone.&lt;br /&gt;
&lt;br /&gt;
It should also be noted that these tests were performed when the CPU was effectively idle. CPU memory copy operations scale down roughly equal with the CPU actively scaling up. So the more the CPU is doing, the longer it takes to complete the memory copy.&lt;br /&gt;
&lt;br /&gt;
Conversely, DMA memory copy operation times are far more predictable as they use the same amount of (minimal) CPU overhead for each copy, and the actual time it takes the DMA hardware to complete the transaction can be calculated to range from all the DMA Channels being idle, to all DMA Channels being busy at once and data moves arbitrating between channels every 1024 bytes.&lt;br /&gt;
&lt;br /&gt;
=== When to use the DMA Engine ===&lt;br /&gt;
&lt;br /&gt;
=== When not to use the DMA Engine ===&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10969</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10969"/>
		<updated>2019-11-16T02:14:20Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* How multiple simultaneous DMA copies are handled */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt line signaling the respective DMA Channel Handler with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it signals completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10968</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10968"/>
		<updated>2019-11-16T02:11:18Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* How multiple simultaneous DMA copies are handled */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt signaling the DMA Channel Handler tasks with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
All eight DMA Channels can handle each a single block transaction or an entire chain of block transactions before it singles completion and returns to the original caller. If all eight DMA Channels are busy processing their requested transactions when further DMA copy requests arrive, they will each be assigned a DMA Channel to wait on (managed via a Mutex lock on each Channel) and will block until allowed to add their DMA transaction to the Channel&#039;s queue.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10967</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10967"/>
		<updated>2019-11-16T02:05:46Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* How multiple simultaneous DMA copies are handled */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
When multiple user calls requesting a DMA copy arrive at once, each one is handed to a dedicated DMA Channel handling task for processing. As the diagram above demonstrates, there are two separate DMA Engines available, each with four channels that may be programmed at the same time. The hardware will then arbitrate the actual data move across these channels according to their respective bandwidth settings (usually 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
In the diagram above, a separate color indicates a distinct data path from the caller through the DMA hardware to the system RAM. A dashed line of the matching color indicates an Interrupt signaling the DMA Channel Handler tasks with the completion of the transaction. The handler task then signals back to the original caller, which returns to the user with a success or failure result.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10966</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10966"/>
		<updated>2019-11-16T01:55:48Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Diagram of multitasking DMA Copies */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10965</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10965"/>
		<updated>2019-11-16T01:52:03Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Diagram of multitasking DMA Copies */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:﻿DMACopyMem-Multitasking-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10964</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10964"/>
		<updated>2019-11-16T01:48:36Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* What a call to perform a DMA copy does internally */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
=== Diagram of multitasking DMA Copies ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Multitasking-Diagram.png﻿]]&lt;br /&gt;
&lt;br /&gt;
=== How multiple simultaneous DMA copies are handled ===&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Multitasking-Diagram.png&amp;diff=10963</id>
		<title>File:DMACopyMem-Multitasking-Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Multitasking-Diagram.png&amp;diff=10963"/>
		<updated>2019-11-16T01:46:38Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: DMA Engine diagram of multiple simultaneous memory copy calls.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;DMA Engine diagram of multiple simultaneous memory copy calls.&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10962</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10962"/>
		<updated>2019-11-16T00:19:49Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* What a call to perform a DMA copy does internally */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result. This provides a basic &#039;&#039;blocking&#039;&#039; function, which only returns to the caller once that data has been copied. This single tasking behavior is the simplest to use and what is normally expected by most applications using a memory copy function.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10961</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10961"/>
		<updated>2019-11-16T00:16:06Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* DMA Copy Memory - Execution Flow Diagram */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
=== What a call to perform a DMA copy does internally ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above diagram, when the user makes a call to request a memory copy be performed by the DMA hardware, the next available DMA Channel is selected for use and a DMA Transaction (source, destination and size) is constructed. The DMA Transaction is then programmed into the DMA Engine which owns the available DMA Channel.&lt;br /&gt;
&lt;br /&gt;
At this point the calling task will Wait() until it hears the transaction has been completed. It will then return to the caller with the result.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10960</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10960"/>
		<updated>2019-11-16T00:02:36Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
=== DMA Copy Memory - Execution Flow Diagram ===&lt;br /&gt;
&lt;br /&gt;
[[File:DMACopyMem-Diagram.png]]&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Diagram.png&amp;diff=10959</id>
		<title>File:DMACopyMem-Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Diagram.png&amp;diff=10959"/>
		<updated>2019-11-16T00:00:01Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: Jamie Krueger uploaded a new version of File:DMACopyMem-Diagram.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diagram of DMA Engine&#039;s Copy Memory function (execution flow)&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Diagram.png&amp;diff=10958</id>
		<title>File:DMACopyMem-Diagram.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=File:DMACopyMem-Diagram.png&amp;diff=10958"/>
		<updated>2019-11-15T23:38:57Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: Diagram of DMA Engine&amp;#039;s Copy Memory function (execution flow)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Diagram of DMA Engine&#039;s Copy Memory function (execution flow)&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10957</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10957"/>
		<updated>2019-11-13T02:17:23Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Obtaining the fsldma.resource */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking the above example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10956</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10956"/>
		<updated>2019-11-13T02:12:22Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Copy Memory Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed. A value of TRUE is returned upon success and FALSE if an error occurred.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10955</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10955"/>
		<updated>2019-11-13T02:10:17Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Memory Management Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned. DMAAllocPhysicalMemory() returns the &#039;&#039;Physical&#039;&#039; Address pointer to the allocated memory or NULL if it is unable to allocate the requested memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10954</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10954"/>
		<updated>2019-11-13T02:01:27Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Hardware Features */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate control between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate control to another Channel, but simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10953</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10953"/>
		<updated>2019-11-13T01:54:26Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Hardware Features */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, as found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate and simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=Autodocs:Main&amp;diff=10952</id>
		<title>Autodocs:Main</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=Autodocs:Main&amp;diff=10952"/>
		<updated>2019-11-13T01:47:03Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The autodocs are included in the latest [[SDK_FAQ|AmigaOS SDK]] and are also available as text files below:&lt;br /&gt;
&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/a1floppy.doc.txt a1floppy.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/a1serial_dev.doc.txt a1serial_dev.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/AI_Driver.doc.txt AI_Driver.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/amigaguide.doc.txt amigaguide.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/amigaguide_dtc.doc.txt amigaguide_dtc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/AmigaInput.doc.txt AmigaInput.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/amiga_lib.doc.txt amiga_lib.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/animation_dtc.doc.txt animation_dtc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/application.doc.txt application.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/arexx_cl.doc.txt arexx_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/asl.doc.txt asl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/audio.doc.txt audio.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/battclock.doc.txt battclock.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/battmem.doc.txt battmem.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/bevel_ic.doc.txt bevel_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/biosversion.doc.txt biosversion.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/bitmap_ic.doc.txt bitmap_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/bsdsocket.doc.txt bsdsocket.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/btree.doc.txt btree.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/bullet.doc.txt bullet.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/button_gc.doc.txt button_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/camd.doc.txt camd.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/cardres.doc.txt cardres.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/cd.doc.txt cd.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/checkbox_gc.doc.txt checkbox_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/chooser_gc.doc.txt chooser_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/cia.doc.txt cia.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/clicktab_gc.doc.txt clicktab_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/clipboard.doc.txt clipboard.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/colorwheel_gc.doc.txt colorwheel_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/commodities.doc.txt commodities.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/console.doc.txt console.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/datatypes.doc.txt datatypes.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/datebrowser_gc.doc.txt datebrowser_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/ddebug_lib.doc.txt ddebug_lib.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/debug_lib.doc.txt debug_lib.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/diffview_gc.doc.txt diffview_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/disk.doc.txt disk.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/diskfont.doc.txt diskfont.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/diskio.doc.txt diskio.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/docky.doc.txt docky.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/dos.doc.txt dos.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/dos.dospackets.doc.txt dos.dospackets.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/dos.obsolete.doc.txt dos.obsolete.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/drawlist_ic.doc.txt drawlist_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/elf.doc.txt elf.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/exec.doc.txt exec.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/expansion.doc.txt expansion.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/filesysbox.doc.txt filesysbox.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/filesysres.doc.txt filesysres.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/filler_ic.doc.txt filler_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/fillrect_ic.doc.txt fillrect_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/frame_ic.doc.txt frame_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/frbutton_gc.doc.txt frbutton_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldmares.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/fuelgauge_gc.doc.txt fuelgauge_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/gadget_gc.doc.txt gadget_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/gadtools.doc.txt gadtools.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/gameport.doc.txt gameport.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/Gameport_pci.doc.txt Gameport_pci.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/gauge_ic.doc.txt gauge_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/getcolor_gc.doc.txt getcolor_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/getfile_gc.doc.txt getfile_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/getfont_gc.doc.txt getfont_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/getscreenmode_gc.doc.txt getscreenmode_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/glyph_ic.doc.txt glyph_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/gradientslider_gc.doc.txt gradientslider_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/graphics.doc.txt graphics.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/group_gc.doc.txt group_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/hunk.doc.txt hunk.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/ibutton_gc.doc.txt ibutton_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/icon.doc.txt icon.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/iconmodule.doc.txt iconmodule.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/ic_cl.doc.txt ic_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/iffparse.doc.txt iffparse.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/image_ic.doc.txt image_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/input.doc.txt input.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/integer_gc.doc.txt integer_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/intuition.doc.txt intuition.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/iscroller_gc.doc.txt iscroller_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/istring_gc.doc.txt istring_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/itext_ic.doc.txt itext_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/keyboard.doc.txt keyboard.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/keymap.doc.txt keymap.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/label_ic.doc.txt label_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/layers.doc.txt layers.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/layout_gc.doc.txt layout_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/libamiga_a.doc.txt libamiga_a.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/listbrowser_gc.doc.txt listbrowser_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/locale.doc.txt locale.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/lowlevel.doc.txt lowlevel.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathffp.doc.txt mathffp.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathieeedoubbas.doc.txt mathieeedoubbas.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathieeedoubtrans.doc.txt mathieeedoubtrans.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathieeesingbas.doc.txt mathieeesingbas.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathieeesingtrans.doc.txt mathieeesingtrans.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/mathtrans.doc.txt mathtrans.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/menu_cl.doc.txt menu_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/misc.doc.txt misc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/model_cl.doc.txt model_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/narrator.doc.txt narrator.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/nonvolatile.doc.txt nonvolatile.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/openfirmware.doc.txt openfirmware.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/page_gc.doc.txt page_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/palette_gc.doc.txt palette_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/parallel.doc.txt parallel.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/partition_gc.doc.txt partition_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/penmap_ic.doc.txt penmap_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/performancemonitor.doc.txt performancemonitor.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/Picasso96API.doc.txt Picasso96API.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/picture_dtc.doc.txt picture_dtc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/pointer_cl.doc.txt pointer_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/popupmenu_cl.doc.txt popupmenu_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/potgo.doc.txt potgo.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/printer.doc.txt printer.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/prop_gc.doc.txt prop_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/radiobutton_gc.doc.txt radiobutton_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/realtime.doc.txt realtime.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/requester_cl.doc.txt requester_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/resource.doc.txt resource.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/rexxsyslib.doc.txt rexxsyslib.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/root_cl.doc.txt root_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/scroller_gc.doc.txt scroller_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/serial_dev.doc.txt serial_dev.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/sketchboard_gc.doc.txt sketchboard_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/slider_gc.doc.txt slider_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/sound_dtc.doc.txt sound_dtc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/space_gc.doc.txt space_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/speedbar_gc.doc.txt speedbar_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/string_gc.doc.txt string_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/sys_ic.doc.txt sys_ic.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/tapedeck_gc.doc.txt tapedeck_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/textclip.doc.txt textclip.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/texteditor_gc.doc.txt texteditor_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/text_dtc.doc.txt text_dtc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/timer.doc.txt timer.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/timesync.doc.txt timesync.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/timezone.doc.txt timezone.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/trackdisk.doc.txt trackdisk.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/translator.doc.txt translator.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/usbfd.doc.txt usbfd.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/usbhcd.doc.txt usbhcd.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/usbresource.doc.txt usbresource.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/usbsys.doc.txt usbsys.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/utility.doc.txt utility.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/virtual_gc.doc.txt virtual_gc.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/warp3d.doc.txt warp3d.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/window_cl.doc.txt window_cl.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/workbench.doc.txt workbench.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/xenares.doc.txt xenares.doc]&lt;br /&gt;
* [http://wiki.amigaos.net/amiga/autodocs/z.doc.txt z.doc]&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10951</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10951"/>
		<updated>2019-11-13T01:46:12Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate and simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
==== Further reference - The fsldma.resource AutoDoc ====&lt;br /&gt;
&lt;br /&gt;
See the [[http://wiki.amigaos.net/amiga/autodocs/fsldmares.doc.txt fsldma.resource AutoDoc]] file for more details on each API call.&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10950</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10950"/>
		<updated>2019-11-13T01:37:50Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate and simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10949</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10949"/>
		<updated>2019-11-13T01:37:10Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Utility / Miscellaneous Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate and simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
&lt;br /&gt;
The last section to the FslDMA API provides a single convenience function call; DMAGetVirtualAddress().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhilight&amp;gt;&lt;br /&gt;
  APTR DMAGetVirtualAddress( APTR pPhysicalAddress );&lt;br /&gt;
&amp;lt;/syntaxhilight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The DMAGetVirtualAddress() function returns the Virtual memory location for the Physical memory location that was itself allocated and returned by the DMAAllocPhysicalMemory() function. DMAGetVirtualAddress() will not work on physical addresses returned by IMMU-&amp;gt;GetPhysicalAddress() on memory not allocated using DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The main purpose of this function (other then debugging purposes) is to provide the &amp;quot;normal&amp;quot; Virtual Address of memory allocated by the FslDMA API for use by functions that expect &amp;quot;normal&amp;quot; Virtual address locations; for example IExec-&amp;gt;CopyMemQuick().&lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10948</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10948"/>
		<updated>2019-11-13T01:28:28Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Copy Memory Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate and simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then setting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10947</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10947"/>
		<updated>2019-11-13T01:26:40Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Copy Memory Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate and simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions one block at a time, then limiting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10946</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10946"/>
		<updated>2019-11-13T01:24:29Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Copy Memory Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate and simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with an unsigned 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions a block at a time, then limiting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10945</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10945"/>
		<updated>2019-11-13T01:23:12Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: /* Copy Memory Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate and simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem().&lt;br /&gt;
Both of these calls will &amp;quot;block&amp;quot; (not return to the user) until after the requested transfer has either succeeded or failed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies the first (and core version) of the copy memory functions, DMAPhysicalCopyMem(), accepts the Physical Addresses to the source and destination buffers (as returned by DMAAllocPhysicalMemory()), along with a 32-Bit value for the amount of bytes that should be copied (lBuffsize must be greater than zero(0) and no more than the maximum size of the source and destination buffers).&lt;br /&gt;
&lt;br /&gt;
DMAPhysicalCopyMem() is the most direct an efficient means of using the DMA hardware to effect a single memory copy. The DMACopyMem() function is provided as an alternative way to request a DMA transfer by passing in the &#039;&#039;Virtual Addresses&#039;&#039; to the source and destination buffers instead of the Physical Addresses. DMACopyMem() will attempt to determine if the supplied memory buffers are DMA Compliant and if so it will internally use DMAPhysicalCopyMem() to handle the transaction. If DMACopyMem() determines that the supplied memory is &#039;&#039;&#039;not&#039;&#039;&#039; DMA Compliant it will return FALSE and no data copy will occur.&lt;br /&gt;
&lt;br /&gt;
In theory any &#039;&#039;contiguous&#039;&#039; block of memory from 1 Byte up to 4GB in size may be transferred using either one of these calls. In practice the DMA hardware can directly accept memory blocks up to FSLDMA_MAXBLOCK_SIZE (or 64MB - 1 Byte). Therefore any data blocks greater than FSLDMA_MAXBLOCK_SIZE will automatically be feed to the DMA hardware in a series of smaller chunks. For maximum efficiency transfer sizes should be at least 256 Bytes in size and be an even multiple of 64 Bytes. Odd sizes are handled by the hardware but will degrade performance.&lt;br /&gt;
&lt;br /&gt;
If you are transferring many large blocks of data in series and wish to manually send them to the FslDMA API&#039;s memory copy functions a block at a time, then limiting your block sizes to FSLDMA_OPTIMAL_BLKSIZE (or 64 MB - 64 Bytes) and exclusively using DMAPhysicalCopyMem() will provide the fastest transfer speeds will the least amount of CPU overhead.&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10944</id>
		<title>DMA Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DMA_Resource&amp;diff=10944"/>
		<updated>2019-11-13T00:54:57Z</updated>

		<summary type="html">&lt;p&gt;Jamie Krueger: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DMA Engine ==&lt;br /&gt;
&lt;br /&gt;
Some hardware targets include a DMA engine which can be used for general purpose copying. This article describes the DMA engines available and how to use them.&lt;br /&gt;
&lt;br /&gt;
=== Hardware Features ===&lt;br /&gt;
&lt;br /&gt;
The Direct Memory Access (DMA) Engines found in the NXP/Freescale p5020, p5040 and p1022 System On a Chip (SoC)s, found in the AmigaONE X5000/20, X5000/40 and A1222 respectively, are quite flexible and powerful. Each of these chips contains two distinct engines with four data channels each. This provides the ability to have a total of eight DMA Channels working at once, with up to two DMA transactions actually being executed at the same time (one on each of the two DMA Engines).&lt;br /&gt;
&lt;br /&gt;
Further, each of the four DMA Channels found in a DMA Engine may be individually programmed to handle either; a single transaction, a &#039;&#039;Chain&#039;&#039; of transactions, or even &#039;&#039;Lists&#039;&#039; of &#039;&#039;Chains&#039;&#039; of transactions. The DMA Engines automatically arbitrate between each DMA Channel following programmed bandwidth settings for each Channel (typically 1024 bytes).&lt;br /&gt;
&lt;br /&gt;
This means that after completing a transfer of 1024 bytes (for example), the hardware will consider switching to the next Channel to allow it to move another block of data, and so on in a round-robin fashion. If all other DMA Channels on a given DMA Engine are idle when arbitration would take place, the hardware will not arbitrate and simply continue processing the transaction(s) for the Channel it is on.&lt;br /&gt;
&lt;br /&gt;
== fsldma.resource ==&lt;br /&gt;
&lt;br /&gt;
The fsldma.resource API is provided automatically in the kernel for all supported machines (Currently the AmigaONE X5000/20, X5000/40 and A1222).&lt;br /&gt;
&lt;br /&gt;
=== The FslDMA API ===&lt;br /&gt;
&lt;br /&gt;
The API provided by the fsldma.resource breaks down into three main parts:&lt;br /&gt;
:* Memory management&lt;br /&gt;
:* Copy Memory functions&lt;br /&gt;
:* Utility / Miscellaneous&lt;br /&gt;
&lt;br /&gt;
==== Memory Management Functions ====&lt;br /&gt;
&lt;br /&gt;
The FslDMA resource API provides convenience functions for the allocation and freeing of &#039;&#039;&#039;DMA Compliant&#039;&#039;&#039; blocks of memory. Two functions are provided for this purpose; DMAAllocPhysicalMemory() and DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
The memory allocation function also includes two Tags based versions of the call to allow for addition variables to be passed into the call using a variable set of Tags or fixed TagList. Currently the only supported Tag is &#039;&#039;FSLDMA_APM_ClearWithValue&#039;&#039;, which is the equivalent to the IExec-&amp;gt;AllocVecTagList() function&#039;s AVT_ClearWithValue tag. If the FSLDMA_APM_ClearWithValue tag is not provided then the requested memory block is cleared with zeroes by default before being returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTagList( uint32 lSize, const struct TagItem *tags );&lt;br /&gt;
  APTR DMAAllocPhysicalMemoryTags( uint32 lSize, uint32 Tag1, ... );&lt;br /&gt;
  APTR DMAAllocPhysicalMemory( uint32 lSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding function to allocating a DMA Compliant memory block is DMAFreePhysicalMemory(). Any memory allocated using DMAAllocPhysicalMemory() must be eventually freed using DMAFreePhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  void DMAFreePhysicalMemory( APTR pPhysicalMemoryBlock );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Copy Memory Functions ====&lt;br /&gt;
&lt;br /&gt;
Two API calls make up the core of the FslDMA API; DMAPhysicalCopyMem() and DMACopyMem()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  BOOL DMAPhysicalCopyMem( CONST_APTR pPhysicalSourceBuffer, APTR pPhysicalDestBuffer, uint32 lBufferSize );&lt;br /&gt;
  BOOL DMACopyMem( CONST_APTR pSourceBuffer, APTR pDestBuffer, uint32 lBufferSize );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Utility / Miscellaneous Functions ====&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
=== Example usage ===&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
// Obtain the fsldma.resource&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
if ( NULL != IfslDMA )&lt;br /&gt;
{&lt;br /&gt;
  uint32     lTestSize         = 1024;&lt;br /&gt;
  CONST_APTR pPhysicalSrcAddr  = NULL;&lt;br /&gt;
  APTR       pPhysicalDestAddr = NULL;&lt;br /&gt;
  // Allocate the Source Buffer (for DMA)&lt;br /&gt;
  // and set the contents to 0xB3 (just an example value)&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
  if ( NULL != pPhysicalSrcAddr )&lt;br /&gt;
  {&lt;br /&gt;
    // Allocate the Destination Buffer (for DMA)&lt;br /&gt;
    //  - contents will by cleared by default&lt;br /&gt;
    pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
    if ( NULL != pPhysicalDestAddr )&lt;br /&gt;
    {&lt;br /&gt;
      // Call IfslDMA-&amp;gt;DMAPhysicalCopyMem()&lt;br /&gt;
      // to perform the memory copy using the DMA hardware&lt;br /&gt;
      if ( TRUE == IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,&lt;br /&gt;
                                               pPhysicalDestAddr,lTestSize) )&lt;br /&gt;
      {&lt;br /&gt;
        // Success - Do something with the copied data&lt;br /&gt;
      }&lt;br /&gt;
      else&lt;br /&gt;
      {&lt;br /&gt;
        // Fallback and use CPU Copy instead (or do something else)&lt;br /&gt;
        // Since we allocated the memory buffers using the FslDMA API,&lt;br /&gt;
        // which returns the Physical address to that memory, and the&lt;br /&gt;
        // IExec-&amp;gt;CopyMemQuick() function expects the Virtual address,&lt;br /&gt;
        // we first need to obtain the Virtual address for the Physical&lt;br /&gt;
        // ones (using the FslDMA API again) before we can call our&lt;br /&gt;
        // fallback copy function.&lt;br /&gt;
        CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
        APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
        pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
        pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
        IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
      }&lt;br /&gt;
      // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
      // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
      IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
    }&lt;br /&gt;
    // We *must* use DMAFreePhysicalMemory() to free the memory&lt;br /&gt;
    // that we allocated with DMAAllocPhysicalMemory()&lt;br /&gt;
    IfslDMA-&amp;gt;DMAFreePhysicalMemory((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtaining the fsldma.resource ====&lt;br /&gt;
&lt;br /&gt;
Breaking this example down the first thing we do is include the interface header for the fsldma.resource and obtain the resource itself.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
#include &amp;lt;interfaces/fsldma.h&amp;gt;&lt;br /&gt;
struct fslDMAIFace *IfslDMA = IExec-&amp;gt;OpenResource(FSLDMA_NAME);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Allocating DMA Compliant Memory ====&lt;br /&gt;
&lt;br /&gt;
Once we have successfully obtained the DMA resource we can directly use its API. The next step we need to do is to allocate some memory &#039;&#039;&#039;which we know is DMA compliant&#039;&#039;&#039; for use by the resource. The easiest way to accomplish this is to use the IfslDMA-&amp;gt;DMAAllocPhysicalMemory() function. This will automatically take care of ensuring the memory that is returned is properly aligned, contiguous, cache-inhibited and coherent.&lt;br /&gt;
&lt;br /&gt;
We use the Tags version of the allocate memory function first so we can allocate a block of memory for our source buffer and fill it with some test value (in this case the byte value 0xB3).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalSrcAddr = (CONST_APTR)IfslDMA-&amp;gt;DMAAllocPhysicalMemoryTags(lTestSize,&lt;br /&gt;
                                   FSLDMA_APM_ClearWithValue, 0xB3,&lt;br /&gt;
                                   TAG_END);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a destination buffer for our test. Since it only needs to start out being cleared (filled with zeroes), we can use the simplest form of the allocate memory function here as the allocated memory is cleared by default.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  pPhysicalDestAddr = IfslDMA-&amp;gt;DMAAllocPhysicalMemory(lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The core function - Copy Physical Memory ====&lt;br /&gt;
&lt;br /&gt;
Now that we have two DMA Compliant memory buffers available we can get to the heart of the API usage and make the call to IfslDMA-&amp;gt;DMAPhysicalCopyMem().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAPhysicalCopyMem(pPhysicalSrcAddr,pPhysicalDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looking at the full [[#Example usage|Example]] source above you can see that the DMAPhysicalCopyMem() call returns a Boolean value to indicate success or failure. Therefore, TRUE will be returned after the DMA hardware had completed copying the requested data (blocking call) and FALSE will be returned if a problem occurred.&lt;br /&gt;
&lt;br /&gt;
Since the memory buffers we are using were allocated using the FslDMA API and our transfer size was greater than zero and less than or equal to the total size of either buffer, (in others words a legal copy request), there is &#039;&#039;&#039;very&#039;&#039;&#039; little chance that the DMAPhysicalCopyMem() function will fail. In fact, about the only reason the DMA hardware would fail to handle a legal transaction would be if the physical RAM installed in the system was faulty.&lt;br /&gt;
&lt;br /&gt;
So even though it is extremely unlikely for our DMA copy to have failed and returned FALSE, let&#039;s take a look at how we might handle the failure. In other words, falling back and using a CPU based copy function instead to complete the data move.&lt;br /&gt;
&lt;br /&gt;
Since we are reverting back to using a normal system copy memory function here, we first need to obtain the &#039;&#039;Virtual Addresses&#039;&#039; to both our source and destination buffers. This is accomplished by using the DMAGetVirtualAddress() function and passing in the Physical Address that was returned by DMAAllocPhysicalMemory().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  CONST_APTR pVirtualSrcAddr  = NULL;&lt;br /&gt;
  APTR       pVirtualDestAddr = NULL;&lt;br /&gt;
  pVirtualSrcAddr  = IfslDMA-&amp;gt;DMAGetVirtualAddress((APTR)pPhysicalSrcAddr);&lt;br /&gt;
  pVirtualDestAddr = IfslDMA-&amp;gt;DMAGetVirtualAddress(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have the Virtual Address equivalents to the Physical Addresses that were returned by DMAAllocPhysicalMemory(), we can proceed to call the Exec CopyMemQuick() function to complete the copy. Here we can only trust that the IExec-&amp;gt;CopyMemQuick() call can not fail since it does not return a result code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IExec-&amp;gt;CopyMemQuick(pVirtualSrcAddr,pVirtualDestAddr,lTestSize);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Cleaning up - Freeing DMA Compliant memory ====&lt;br /&gt;
&lt;br /&gt;
It is essential that you free any memory that was allocated using the DMAAllocPhysicalMemory() function using the corresponding DMAFreePhysicalMemory() call. The reason for this is two-fold; first because additional resource tracking is maintained by the FslDMA API whenever it allocates memory which must itself be released, and second because the &#039;&#039;Physical Address&#039;&#039; to the memory is returned by the allocate call and not the &#039;&#039;Virtual Address&#039;&#039;, so if you attempt to pass the address returned by DMAAllocPhysicalMemory() directly into IExec-&amp;gt;FreeVec() it would likely result in a crash.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalSrcAddr);&lt;br /&gt;
  IfslDMA-&amp;gt;DMAFreePhysicalMemory(pPhysicalDestAddr);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jamie Krueger</name></author>
	</entry>
</feed>