diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-0D2F811C-81C3-526F-8EA4-98E50261BF4B.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-0D2F811C-81C3-526F-8EA4-98E50261BF4B.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,282 @@ + + + + + +DMA +Framework TechnologyDescribes the classes that the DMA Framework provides to transfer +data using DMA. +

The following diagram shows the general relationship between the various +classes and structs that form the DMA Framework. The individual items are +described in more detail below.

+ + + +
The DMA Software +Controller

This is the TDmac object. It has +two purposes:

    +
  • It defines the main +interface between the platform independent and platform specific layers.

  • +
  • it is a container for +channels, descriptors and descriptor headers

  • +
+
The Channel +Manager

The channel manager is a DmaChannelMgr object.

DmaChannelMgr is +a static class defined by the platform independent layer but implemented in +the platform specific layer. The functionality is used by the platform independent +layer. It contains:

    +
  • a function to open a +DMA channel: DmaChannelMgr::Open()

  • +
  • a function that is called +when a channel is closed: DmaChannelMgr::Close()

  • +
  • a function that can +be used to extend the framework with platform specific functionality on a +channel independent basis: DmaChannelMgr::StaticExtension()

  • +
+
Descriptors

DMA +controllers operating in scatter/gather mode are configured via a linked list +of small data structures describing the data to be transferred. These data +structures are called descriptors. (Note that the use of the term descriptor +in the context of DMA should not be confused with the same term widely used +in Symbian platform to refer to the family of TDesC derived +classes).

The Symbian platform DMA Framework always uses descriptor +data structures to store transfer-configuration-information, even if the underlying +DMA controller does not support scatter/gather mode.

The following +example illustrates the idea: assume that a device driver needs to transfer +two disjoint blocks of memory, A and B, into another block C. Block A starts +at address 1000 and is 300 bytes long. Block B starts at address 2000 and +is 700 bytes long. The destination buffer C starts at address 5000 and is +1000 bytes long. Assume that the DMA descriptors are allocated in a pool starting +at address 600. The following diagram shows the scatter/gather list that the +device driver might create:

+ +

If the DMA controller supports the scatter/gather arrangement, then +the framework uses a structure that will be specific to the hardware. This +structure is defined in the platform specific layer.

If the DMA controller +does not support scatter/gather, then the framework uses the generic structure SDmaPseudoDes containing +the following information:

    +
  • a set of generic flags +that characterise the transfer. For example, is the source of the data memory +or a peripheral; is the destination memory or peripheral; what addressing +mode is to be used?

  • +
  • the source and destination +location. This is in the form of the base virtual address for a memory buffer, +and a 32-bit value (or cookie) for peripherals. The meaning of the 32-bit +value is interpreted by the platform specific layer.

  • +
  • The number of bytes +to be transferred.

  • +
  • A word that only has +meaning for the platform specific layer, and passed by the client at request +fragmentation time.

  • +
+
Descriptor +headers

These are objects of type SDmaDesHdr.

A +descriptor header allows additional information about a descriptor to be stored. +The header is a separate object from the descriptor because it is difficult +to embed additional data in a structure whose layout may be hardware-imposed.

Descriptors +and descriptor headers are stored in two parallel arrays allocated at boot-time, +and each descriptor is always associated with the header of same index, so +that there is always a one-to-one relationship between the header and the +descriptor.

+ +

In the current design, the only information in the descriptor header +is a pointer, SDmaDesHdr::iNext, that is used to chain headers +together on various lists. So, although the pool of headers is allocated as +an array, they are almost always accessed by following the chain of pointers +linking one header to the next.

Descriptors are always accessed +through their associated header.

The platform independent layer never +directly accesses hardware-specific descriptors. It just passes descriptor +headers to the platform specific layer. However, the platform independent +layer does directly manipulate the generic descriptors, SDmaPseudoDes.

+
Transfer Requests

A +transfer request is the way in which a device driver sets up and initiates +a DMA transfer, and is represented by a DDmaRequest object.

A +transfer request has a number of characteristics:

    +
  • it is always associated +with exactly one channel.

  • +
  • it stores a client-provided +callback function, which is invoked when the whole request completes, whether +successfully or not.

  • +
  • it can be in one of +four states:

      +
    • not configured

    • +
    • idle

    • +
    • being transferred

    • +
    • pending; this state +only occurs in streaming mode.

    • +
  • +

Internally, a transfer request is represented as a singly linked +list of descriptor headers. Each header in the list is associated with a descriptor +that specifies how to transfer one fragment of the whole request. Transfer +requests have pointers to the first and last headers in the list.

When +the request is idle, the header list ends with a NULL pointer. This is not +always true when the request is queued (i.e. when the request is being transferred +or is still pending). The following diagram shows an idle request with three +fragments.

+ +

Splitting a request into fragments is useful because:

    +
  • it insulates device +drivers from the maximum transfer size supported by the underlying DMA controller.

  • +
  • the source and destination +DMA buffers may not be physically contiguous and thus require fragmenting.

  • +

Both of these situations can be handled by using the generic fragmentation +algorithm DDmaRequest::Fragment().

Some device +drivers may have to create custom descriptors lists. For example, the USB +section of the PXA250 manual describes how to build custom lists where a descriptor +containing data transfer information is followed by another one poking an +I/O port to issue a command to the USB controller.

To cover that case, DDmaRequest provides +the DDmaRequest::ExpandDesList() member function to allocate +a list of headers associated with blank descriptors whose content is then +set by device drivers. Blank descriptors thus created can be accessed in the +following way (this example was taken and simplified from the PXA250 USB controller +driver):

TDmaChannel* channel; +TDmaChannel::SCreateInfo info; +info.x = y; +if (TDmaChannel::Open(info, channel) != KErrNone) + ... return; +DDmaRequest* req = new DDmaRequest(*channel); +if (!req) + ... return; +const TDmac* dmac = req->iChannel.Controller(); +if (req->ExpandDesList(2) != KErrNone) + ... return; +TDmaDesc* desc1 = static_cast<TDmaDesc*>(dmac->HdrToHwDes(*req->iFirstHdr)); +TDmaDesc* desc2 = static_cast<TDmaDesc*>(dmac->HdrToHwDes(*req->iFirstHdr->iNext)); +desc1->iSrcAddr = ...; +desc1->iDestAddr = ...; +desc1->iDescAddr = ...; +desc1->iCmd = ...; +desc2... +... +
+
Channels

A +channel is a TDmaChannel object, and there is one of these +for each hardware DMA channel.

A channel can be in one of 4 states:

    +
  • closed

  • +
  • open and idle

  • +
  • open and transferring +data

  • +
  • suspended following +an error.

  • +

On opening a channel, the client device driver specifies:

    +
  • A 32-bit value (cookie) +that is used by the platform specific layer to select which channel is to +be opened

  • +
  • The number of descriptors +that must be reserved for this channel.

  • +
  • A DFC to be used by +the framework to service DMA interrupts.

  • +

A channel maintains a queue of transfer requests. If the channel +is being used for one-shot transfers, the queue will always contain an idle +or a transferring request. In streaming mode, the queue may contain several +requests, the first one being transferred and the remaining ones pending. +When a request is completely transferred, it is removed from the queue. The +first request is always the one being transferred.

A transferring +channel has a pointer to the header associated with the descriptor being transferred. +The headers of all queued requests are linked together on one linked list.

The +following diagram shows a DMA channel with a three-fragment request being +transferred and a two-fragment one pending. The fragment currently being transferred +is the second one of the first request.

+ +

The TDmaChannel class contains the code and data +that is common to all of the channel types. The code and data for the specific +channel types: single buffer, double buffer, and scatter/gather channels, +are implemented in the derived classes: TDmaSbChannel, TDmaDbChannel, +and TDmaSgChannel respectively.

TDmaSbChannel +State Machine

For reference purposes, the following diagram shows +the state machine that TDmaSbChannel implements to deal +with a single buffer channel.

+ +

TDmaDbChannel +State Machine

For reference purposes, the following diagram shows +the state machine that TDmaDbChannel implements to deal +with a double buffer channel.

+ +

TDmaSgChannel +State Machine

For reference purposes, the following diagram shows +the state machine that TDmaSgChannel implements to deal +with a scatter/gather channel.

+ +
+
Streaming and +Scatter/Gather DMA Controllers

When a transfer request is queued +onto a channel that is already transferring data, the header descriptor for +the new list of descriptors is appended to the header of the previous request +on the queue. If the underlying DMA controller supports hardware descriptors, +they must also be linked together.

The following diagram shows how +headers and descriptors for a new request are appended to the existing ones +for a DMA controller. The dashed arrows represent the new links.

+ +

Note that hardware descriptors are linked together using physical +addresses, not virtual ones.

Linking hardware descriptors together +is implemented in the platform specific layer. There are two issues to consider:

    +
  • The channel may go idle +before the linking is complete, which means that the data for the new request +would not be transferred.

  • +
  • If the channel is transferring +the last descriptor in the list, then updating the “next” field in the descriptor +will have no effect because the content of the descriptor will already have +been loaded in the controller registers. Again the channel would go idle without +transferring the data associated with the new request.

  • +

The solutions available when porting the DMA Framework are:

    +
  • If the DMA controller +has hardware support for appending descriptors while transferring data, then +there is no problem.

  • +
  • If the peripheral attached +to the channel can withstand a short disruption in the transfer flow, then +the channel can be suspended while the appending takes place. This should +be done with interrupts disabled to minimise disruption.

  • +
  • The alternative technique +is to append the new list with interrupts disabled and set a flag. When the +next interrupt occurs, if the flag is set and the channel idle, then the interrupt +service routine must restart the transfer.

  • +

See Channels.

+
Interrupt Service +Routine (ISR) and DFC Issues

The platform specific layer must notify +the platform independent layer when the following events occur:

    +
  • when an error occurs.

  • +
  • when each fragment completes, +for single-buffer and double-buffer controllers.

  • +
  • when the last fragment +of a request completes, for scatter/gather controllers.

  • +

The ISR, as implemented in the platform specific layer, must:

    +
  • determine which channel +the interrupt is for. If the DMA controller uses dedicated interrupt lines +per channel, the ASSP/variant interrupt dispatcher will do this. See Interrupt Dispatcher Tutorial.

  • +
  • determine whether the +interrupt was asserted following a successful transfer completion or a failure. +If the DMA controller uses different interrupt lines for completion and failure, +the ASSP/variant interrupt dispatcher will do this.

  • +
  • Call TDmac::HandleIsr() in +the platform specific layer. This function queues the DFC associated with +the relevant channel. It takes care of the case where several interrupts occur +before the DFC gets a chance to run.

  • +

The DFC updates the state of the channel and, for single and double +buffer DMA controllers, configures the next fragment to transfer, if any. +When all fragments making up a request have been transferred, the DFC calls +the client-supplied callback associated with the completed request. The callback +is also called if an error occurs during transfer.

+
Locking Strategy

For +a given device driver, TDmaChannel and DDmaRequest instances +can be accessed concurrently from the device driver thread and from a DFC +queue thread. To avoid race conditions, each TDmaChannel instance +has a fast mutex, the protected data member TDmaChannel::iLock. +This lock is acquired when queuing a new request, cancelling requests and +executing the DFC.

TDmaChannel and DDmaRequest instances +are not protected against concurrent access from several client threads because +this is assumed to be an exceptional case. A device driver with such need +would have to implement its own locking scheme around calls to TDmaChannel and DDmaRequest member +functions.

Each TDmac instance includes a fast +mutex, the private member TDmac::iLock to protect descriptor +reservation and allocation, because several device drivers may try to reserve +or allocate descriptors concurrently.

The DmaChannelMgr static +class includes a fast mutex which is used to protect channel opening as several +device drivers may compete for the same channel. This lock is also used at +channel closing time.

+
\ No newline at end of file