diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-E7E67A52-0725-446B-A49C-CF571C4A0C64.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-E7E67A52-0725-446B-A49C-CF571C4A0C64.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,86 @@ + + + + + +DMA +Buffer OperationsThis document describes how a device driver allocates and deallocates +DMA buffers. +
Allocation

DMA +requires contiguous memory chunks to be allocated to do copy and read operations. +A driver can do this by using the Symbian Kernel API. A contiguous block of +memory can be allocated using Epoc::AllocPhysicalRam(), +which provides the physical address of the contiguous memory block allocated.

After +allocating the buffer, a global hardware chunk must be created, and its attributes +set. The attributes define chunk properties such as whether it is non-cacheable, +or whether it can be accessed only in supervisor mode, and so on.

TInt DExDriverUartTxDma::Init() + { + // Round up the transmit chunk size to the page size. + // Kern::RoundToPageSize() rounds up the argument to the size of + // a MMU page. The size of one MMU page can be found out by calling + // Kern::RoundToPageSize(1). + // + iTxBufSize = Kern::RoundToPageSize (KRxTxDMABufferSize); + + // Epoc::AllocPhysicalRam() allocate contiguous physical memory + // for the transmit buffer of the specified size, and returns the physical address + // of the buffer. We need contiguous block of memory and its + // physical address for DMA. + // + TInt r = Epoc::AllocPhysicalRam (iTxBufSize, iTxPhysAddr); + if (r != KErrNone) + { + return r; + } + + // Create a global hardware chunk for the buffer allocated using + // Epoc::AllocPhysicalRam() and set attributes to make it + // uncached and accessible only by kernel-side code. + // Contiguous, uncached, unbuffereable RAM pages avoids + // coherency and fragmentation issues while using DMA. + // However, in case of making buffers cacheable other APIs are + // provided to synch, i.e. flush cache before doing a DMA + // transfer + // + r = DPlatChunkHw::New(iTxChunk, iTxPhysAddr, iTxBufSize, + EMapAttrSupRw // Supervisor mode, user has no access + |EMapAttrFullyBlocking); // uncached, unbuffered + if (r != KErrNone) + { + // Free the allocated RAM, that was earlier allocated by + // Epoc::AllocPhysicalRam(). + Epoc::FreePhysicalRam(iTxPhysAddr, iTxBufSize); + return r; + } + ... + }

Buffers can also be made cacheable, in which case, the +driver has to ensure to synchronise by flushing the cache before writing and +after reading.

// Synchronises cache(s) prior to a DMA write operation. i.e. +// before DMA is used write to a peripheral data which is read +// from RAM. +void Cache::SyncMemoryBeforeDmaWrite(TLinAddr aBase, + TUint aSize, TUint32 aMapAttr) + +// Synchronizes cache(s) prior to a DMA read operation. +// i.e. before DMA is used read from a peripheral data which is +// written to RAM. +void Cache::SyncMemoryBeforeDmaRead(TLinAddr aBase, + TUint aSize, TUint32 aMapAttr) + +// Synchronises cache(s) after a DMA read operation. +void Cache::SyncMemoryAfterDmaRead(TLinAddr aBase, TUint aSize)

However, +unless required by design, DMA chunks are used in non-cacheable and non-buffered +mode.

+
Deallocation

DMA buffers have to be deallocated +when they are no longer used. Buffers are deallocated in the physical channel +destructor.

Like allocation, deallocation is performed in two stages. +When you allocate, the contiguous buffer is allocated and a hardware chunk +is created; when you de-allocate, the contiguous buffer is deallocated and +the chunk is closed.

+
\ No newline at end of file