Adaptation/GUID-0D2F811C-81C3-526F-8EA4-98E50261BF4B.dita
author Graeme Price <GRAEME.PRICE@NOKIA.COM>
Fri, 15 Oct 2010 14:32:18 +0100
changeset 15 307f4279f433
permissions -rw-r--r--
Initial contribution of the Adaptation Documentation.

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-0D2F811C-81C3-526F-8EA4-98E50261BF4B" xml:lang="en"><title>DMA
Framework Technology</title><shortdesc>Describes the classes that the DMA Framework provides to transfer
data using DMA. </shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<p>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. </p>
<fig id="GUID-C6B032F0-7E05-5E29-8024-B713C42A2434">
<image href="GUID-D43AB2F5-32AE-540C-80D8-DE8B2072F1E6_d0e10612_href.png" placement="inline"/>
</fig>
<section id="GUID-D9855D5F-3D4D-5A65-A1BB-B7CB94E60316"><title>The DMA Software
Controller</title> <p>This is the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> object. It has
two purposes: </p> <ul>
<li id="GUID-E4C8A5C5-192B-5E3E-A2F1-D884BF7FE641"><p>It defines the main
interface between the platform independent and platform specific layers. </p> </li>
<li id="GUID-98888CE1-5AA6-5D91-A5C5-E60F1200465A"><p>it is a container for
channels, descriptors and descriptor headers </p> </li>
</ul> </section>
<section id="GUID-37DF82BE-5F8E-5497-90E8-C48F44C2A7F1"><title>The Channel
Manager</title> <p>The channel manager is a <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita"><apiname>DmaChannelMgr</apiname></xref> object. </p> <p> <codeph> DmaChannelMgr</codeph> 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: </p> <ul>
<li id="GUID-B5626DA4-1465-5469-BE3D-36F31996C75A"><p>a function to open a
DMA channel: <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-934F46B3-1DF9-3870-87EE-A8E2DEF82810"><apiname>DmaChannelMgr::Open()</apiname></xref>  </p> </li>
<li id="GUID-67C7DE2F-196E-5919-BA80-99898DF6837D"><p>a function that is called
when a channel is closed: <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-909D795A-7303-3A76-9C8E-3B07A97DD716"><apiname>DmaChannelMgr::Close()</apiname></xref>  </p> </li>
<li id="GUID-F044E05A-A307-51B0-BDD5-8A29A950BE5F"><p>a function that can
be used to extend the framework with platform specific functionality on a
channel independent basis: <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-C733B302-4269-3391-8ADE-617CFF198B56"><apiname>DmaChannelMgr::StaticExtension()</apiname></xref>  </p> </li>
</ul> </section>
<section id="GUID-34B8E965-9C5C-533E-BFE6-EB9B486A81BB"><title>Descriptors</title> <p>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 <xref href="GUID-52D07F46-2162-380C-A775-C3BB335C42F5.dita"><apiname>TDesC</apiname></xref> derived
classes). </p> <p>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. </p> <p>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: </p> <fig id="GUID-966DC875-FA9E-59E5-A1CA-842F4A82592D">
<image href="GUID-EA0C5715-7CE8-5415-A915-D5701E3C957A_d0e10709_href.png" placement="inline"/>
</fig> <p>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. </p> <p>If the DMA controller
does not support scatter/gather, then the framework uses the generic structure <xref href="GUID-D7934AD9-38F6-325A-A734-F867D886D7C2.dita"><apiname>SDmaPseudoDes</apiname></xref> containing
the following information: </p> <ul>
<li id="GUID-D5EA7DC2-FC49-5FF3-95FE-6E5426D25BFF"><p>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? </p> </li>
<li id="GUID-4D54D3E6-0252-5F15-9966-E7F09A10020E"><p>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. </p> </li>
<li id="GUID-416CB113-5973-50AD-9FF3-F3AF78B47D0C"><p>The number of bytes
to be transferred. </p> </li>
<li id="GUID-D76CE2CE-5005-5C2F-B17D-F882D6BD7EB8"><p>A word that only has
meaning for the platform specific layer, and passed by the client at request
fragmentation time. </p> </li>
</ul> </section>
<section id="GUID-BC1C248D-170D-51AE-B2E5-61FFEC779D61"><title>Descriptor
headers</title> <p>These are objects of type <xref href="GUID-710B3501-FF22-307D-AC88-D142E9A07CB8.dita"><apiname>SDmaDesHdr</apiname></xref>. </p> <p>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. </p> <p>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. </p> <fig id="GUID-A635E3EA-883C-5857-8690-E0AE6F43CAC4">
<image href="GUID-99F7E70F-2733-57B2-94F5-A0C0FF9219FE_d0e10765_href.png" placement="inline"/>
</fig> <p>In the current design, the only information in the descriptor header
is a pointer, <codeph>SDmaDesHdr::iNext</codeph>, 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. </p> <p>Descriptors are <i>always</i> accessed
through their associated header. </p> <p>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, <xref href="GUID-D7934AD9-38F6-325A-A734-F867D886D7C2.dita"><apiname>SDmaPseudoDes</apiname></xref>. </p> </section>
<section id="GUID-F4685621-1FAA-544C-B4C0-B4DD566B856F"><title>Transfer Requests</title> <p>A
transfer request is the way in which a device driver sets up and initiates
a DMA transfer, and is represented by a <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita"><apiname>DDmaRequest</apiname></xref> object. </p> <p>A
transfer request has a number of characteristics: </p> <ul>
<li id="GUID-D5B73919-B6C8-54F9-8C1E-87467E32EAA0"><p>it is always associated
with exactly one channel. </p> </li>
<li id="GUID-FE3326FA-B0CF-50A2-BD4D-72F868226EFB"><p>it stores a client-provided
callback function, which is invoked when the whole request completes, whether
successfully or not. </p> </li>
<li id="GUID-627B7D15-0119-5D72-A517-84832D90C3D1"><p>it can be in one of
four states: </p> <ul>
<li id="GUID-1D600F30-F06C-58FB-B258-8167164FE1FC"><p>not configured </p> </li>
<li id="GUID-194A4B9A-12E6-50B6-816A-73717CD100F9"><p>idle </p> </li>
<li id="GUID-0B7A0249-9F5D-5D5D-AB3C-4DDE8AFC58E6"><p>being transferred </p> </li>
<li id="GUID-AF57DDF1-406D-55D4-A001-F62921165189"><p>pending; this state
only occurs in streaming mode. </p> </li>
</ul> </li>
</ul> <p>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. </p> <p>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. </p> <fig id="GUID-0A5594BD-05E4-5A97-A3F7-459E3F8638A2">
<image href="GUID-CF252B09-335E-5831-94A6-0B16B64C5030_d0e10851_href.png" placement="inline"/>
</fig> <p>Splitting a request into fragments is useful because: </p> <ul>
<li id="GUID-BEA0F4C5-4308-54E9-82AB-91570ACC9ADC"><p>it insulates device
drivers from the maximum transfer size supported by the underlying DMA controller. </p> </li>
<li id="GUID-A768A76B-DD9E-5A25-92D3-23A69299C096"><p>the source and destination
DMA buffers may not be physically contiguous and thus require fragmenting. </p> </li>
</ul> <p>Both of these situations can be handled by using the generic fragmentation
algorithm <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita#GUID-780F4D53-5546-3B69-B328-0226C70EBDE2/GUID-B14B0478-80D6-3F5E-88B6-1676411D9CF2"><apiname>DDmaRequest::Fragment()</apiname></xref>. </p> <p>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. </p> <p>To cover that case, <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita"><apiname>DDmaRequest</apiname></xref> provides
the <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita#GUID-780F4D53-5546-3B69-B328-0226C70EBDE2/GUID-AAB7C209-7D30-3282-B084-D80E12BB5152"><apiname>DDmaRequest::ExpandDesList()</apiname></xref> 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): </p> <codeblock id="GUID-EFA935A1-0D7E-5153-9071-2D0C58E8E920" xml:space="preserve">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-&gt;iChannel.Controller();
if (req-&gt;ExpandDesList(2) != KErrNone)
    ... return;
TDmaDesc* desc1 = static_cast&lt;TDmaDesc*&gt;(dmac-&gt;HdrToHwDes(*req-&gt;iFirstHdr));
TDmaDesc* desc2 = static_cast&lt;TDmaDesc*&gt;(dmac-&gt;HdrToHwDes(*req-&gt;iFirstHdr-&gt;iNext));
desc1-&gt;iSrcAddr  = ...;
desc1-&gt;iDestAddr = ...;
desc1-&gt;iDescAddr = ...;
desc1-&gt;iCmd      = ...;
desc2...
...
</codeblock> </section>
<section id="GUID-4BF7605E-55D4-5B3A-BCD7-1F976765D738"><title>Channels</title> <p>A
channel is a <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita"><apiname>TDmaChannel</apiname></xref> object, and there is one of these
for each hardware DMA channel. </p> <p>A channel can be in one of 4 states: </p> <ul>
<li id="GUID-09581FA5-D01A-502A-9841-52ABDF0BB16E"><p>closed </p> </li>
<li id="GUID-D03F51BA-1493-5B23-B029-4FF5FCC4DE5E"><p>open and idle </p> </li>
<li id="GUID-606FA290-FB8D-5CBE-88C2-BCD03062EE25"><p>open and transferring
data </p> </li>
<li id="GUID-2E845C88-292D-54B9-9F99-AAC3775768E4"><p>suspended following
an error. </p> </li>
</ul> <p>On opening a channel, the client device driver specifies: </p> <ul>
<li id="GUID-6F373D39-4078-5C76-BF5E-69294297D8CE"><p>A 32-bit value (cookie)
that is used by the platform specific layer to select which channel is to
be opened </p> </li>
<li id="GUID-71E4D026-4BA5-592B-BB3E-5F5354640E50"><p>The number of descriptors
that must be reserved for this channel. </p> </li>
<li id="GUID-4C34A82A-AF7E-5683-986B-A65EA6C8F5B2"><p>A DFC to be used by
the framework to service DMA interrupts. </p> </li>
</ul> <p>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. </p> <p>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. </p> <p>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. </p> <fig id="GUID-36E11A64-4626-53F9-925C-3DC323DEA895">
<image href="GUID-86C21C9B-9F08-579F-84E9-CBE46F756373_d0e10964_href.png" placement="inline"/>
</fig> <p>The <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita"><apiname>TDmaChannel</apiname></xref> 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: <xref href="GUID-A8B4AD1B-770C-363E-A0DE-C78A9786CBDC.dita"><apiname>TDmaSbChannel</apiname></xref>, <xref href="GUID-FD76AF08-6250-3054-8A06-16343E385B23.dita"><apiname>TDmaDbChannel</apiname></xref>,
and <xref href="GUID-2D4CFBB1-8D64-3CF5-B6F0-B24D16D5BAD4.dita"><apiname>TDmaSgChannel</apiname></xref> respectively. </p> <p><b>TDmaSbChannel
State Machine</b> </p> <p>For reference purposes, the following diagram shows
the state machine that <xref href="GUID-A8B4AD1B-770C-363E-A0DE-C78A9786CBDC.dita"><apiname>TDmaSbChannel</apiname></xref> implements to deal
with a single buffer channel. </p> <fig id="GUID-82A8742D-CE5E-5EA2-A19E-6DCA30D9AE61">
<image href="GUID-85332468-292D-589B-891B-0E7ACBADC7BA_d0e11000_href.png" placement="inline"/>
</fig> <p><b>TDmaDbChannel
State Machine</b> </p> <p>For reference purposes, the following diagram shows
the state machine that <xref href="GUID-FD76AF08-6250-3054-8A06-16343E385B23.dita"><apiname>TDmaDbChannel</apiname></xref> implements to deal
with a double buffer channel. </p> <fig id="GUID-1CF4D292-310C-5D75-9E3B-2DB65217FEEA">
<image href="GUID-91958EA5-9444-5895-B4B8-F2C670B81CD7_d0e11017_href.png" placement="inline"/>
</fig> <p><b>TDmaSgChannel
State Machine</b> </p> <p>For reference purposes, the following diagram shows
the state machine that <xref href="GUID-2D4CFBB1-8D64-3CF5-B6F0-B24D16D5BAD4.dita"><apiname>TDmaSgChannel</apiname></xref> implements to deal
with a scatter/gather channel. </p> <fig id="GUID-1206C662-9856-57A1-A0C5-FDF74F2A3BD3">
<image href="GUID-09EE01E2-BF5E-5302-BA25-46C440ADECF5_d0e11034_href.png" placement="inline"/>
</fig> </section>
<section id="GUID-2F8979D3-A4DC-5919-B027-F8C17739A05D"><title>Streaming and
Scatter/Gather DMA Controllers</title> <p>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. </p> <p>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. </p> <fig id="GUID-7E06E92E-C8D1-53FF-AF03-5B1A3EBC1EA5">
<image href="GUID-28F3F720-A2E0-59C9-8BB4-B6124CFC6C89_d0e11050_href.png" placement="inline"/>
</fig> <p> <i>Note that hardware descriptors are linked together using physical
addresses, not virtual ones.</i>  </p> <p>Linking hardware descriptors together
is implemented in the platform specific layer. There are two issues to consider: </p> <ul>
<li id="GUID-4236DD82-FFAD-56D3-B46F-9D2198E0349A"><p>The channel may go idle
before the linking is complete, which means that the data for the new request
would not be transferred. </p> </li>
<li id="GUID-48AAA44F-1EEF-5899-9D62-587AA0EC8303"><p>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. </p> </li>
</ul> <p>The solutions available when porting the DMA Framework are: </p> <ul>
<li id="GUID-DC8EBCE6-E355-5D93-A265-0D591F06841C"><p>If the DMA controller
has hardware support for appending descriptors while transferring data, then
there is no problem. </p> </li>
<li id="GUID-77DE96E7-9D9A-543F-8CD9-A36055F38E7A"><p>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. </p> </li>
<li id="GUID-962DAD2E-2684-5F51-8F80-A1E3C86BC8F7"><p>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. </p> </li>
</ul> <p>See <xref href="GUID-0D2F811C-81C3-526F-8EA4-98E50261BF4B.dita#GUID-0D2F811C-81C3-526F-8EA4-98E50261BF4B/GUID-4BF7605E-55D4-5B3A-BCD7-1F976765D738">Channels</xref>. </p> </section>
<section id="GUID-106BBBE0-C18B-5321-96AE-F1A65FAB4FF7"><title>Interrupt Service
Routine (ISR) and DFC Issues</title> <p>The platform specific layer must notify
the platform independent layer when the following events occur: </p> <ul>
<li id="GUID-13589C1E-5146-5044-9587-092C4347D4EC"><p>when an error occurs. </p> </li>
<li id="GUID-47C15152-8C06-5864-9292-4EF6A9A458E6"><p>when each fragment completes,
for single-buffer and double-buffer controllers. </p> </li>
<li id="GUID-BCDD4ECD-4396-5F2C-9A3A-B0C3B20DCC90"><p>when the last fragment
of a request completes, for scatter/gather controllers. </p> </li>
</ul> <p>The ISR, as implemented in the platform specific layer, must: </p> <ul>
<li id="GUID-037B8F96-3C27-5D2F-8E70-35C66C601D63"><p>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 <xref href="GUID-3C34724F-B476-5329-B0B1-6D5A34294979.dita">Interrupt Dispatcher Tutorial</xref>. </p> </li>
<li id="GUID-58A2D3AE-BF42-56E6-9EB1-B77DC9B2B934"><p>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. </p> </li>
<li id="GUID-F9D50FBF-171A-5D26-851E-3FDDB4AE38BB"><p>Call <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-187EBCEB-4488-3606-BB71-8813111D8AF4"><apiname>TDmac::HandleIsr()</apiname></xref> 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. </p> </li>
</ul> <p>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. </p> </section>
<section id="GUID-2CB7E268-0535-5AD0-8B08-3FEDBA39016D"><title>Locking Strategy</title> <p>For
a given device driver, <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita"><apiname>TDmaChannel</apiname></xref> and <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita"><apiname>DDmaRequest</apiname></xref> instances
can be accessed concurrently from the device driver thread and from a DFC
queue thread. To avoid race conditions, each <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita"><apiname>TDmaChannel</apiname></xref> instance
has a fast mutex, the protected data member <codeph>TDmaChannel::iLock</codeph>.
This lock is acquired when queuing a new request, cancelling requests and
executing the DFC. </p> <p> <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita"><apiname>TDmaChannel</apiname></xref> and <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita"><apiname>DDmaRequest</apiname></xref> 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 <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita"><apiname>TDmaChannel</apiname></xref> and <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita"><apiname>DDmaRequest</apiname></xref> member
functions. </p> <p>Each <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> instance includes a fast
mutex, the private member <codeph>TDmac::iLock</codeph> to protect descriptor
reservation and allocation, because several device drivers may try to reserve
or allocate descriptors concurrently. </p> <p>The <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita"><apiname>DmaChannelMgr</apiname></xref> 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. </p> </section>
</conbody></concept>