--- a/kernel/eka/include/drivers/dma.h Mon Jun 21 17:12:14 2010 +0300
+++ b/kernel/eka/include/drivers/dma.h Thu Jul 15 20:11:42 2010 +0300
@@ -333,27 +333,67 @@
virtual void DoUnlink(SDmaDesHdr& aHdr);
virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr) = 0;
/**
- This function allows the Platform Specific Layer (PSL) to control the
- power management of the channel or its controller by overriding the
- PIL's default implementation (which does nothing) and making appropriate
- use of the Power Resource Manager (PRM).
+ This function allows the Platform Specific Layer (PSL) to control the
+ power management of the channel or its controller by overriding the
+ PIL's default implementation (which does nothing) and making
+ appropriate use of the Power Resource Manager (PRM).
+
+ The function gets called by the PIL whenever the channel's queued
+ requests count has changed in a significant way, either before the
+ channel's Transfer() method is invoked for a request on a previously
+ empty request queue, or immediately after the request count has become
+ zero because of request cancellation or completion.
+
+ Depending on the current and previous observed values of
+ iQueuedRequests, the PSL may power down or power up the channel.
- The function gets called by the PIL whenever the channel's queued
- requests count has changed in a significant way, either before the
- channel's Transfer() method is invoked for a request on a previously
- empty request queue, or immediately after the request count has become
- zero because of request cancellation or completion.
+ Note that iQueuedRequests gets accessed and changed by different
+ threads, so the PSL needs to take the usual precautions when evaluating
+ the variable's value. Also, due to the multithreaded framework
+ architecture, there is no guarantee that the function calls always
+ arrive at the PSL level in the strict chronological order of
+ iQueuedRequests being incremented/decremented in the PIL, i.e. it might
+ happen that the PSL finds iQueuedRequests to have the same value in two
+ or more consecutive calls (that's why the previous observed value needs
+ to be locally available and taken into account). It is however promised
+ that before any actual transfer commences the PSL will find the request
+ count to be greater than zero and that after the last request has
+ finished it will be found to be zero.
+
+ None of the internal DMA framework mutexes is being held by the PIL
+ when calling this function.
- Depending on the current value of iQueuedRequests, the PSL may power
- down or power up the channel. Note that iQueuedRequests gets accessed
- and changed by different threads, so the PSL needs to take the usual
- precautions when evaluating the variable's value.
+ Here is an example implementation for a derived channel class:
+
+ @code
+
+ class TFooDmaChannel : public TDmaSgChannel
+ {
+ DMutex* iDmaMutex;
+ TInt iPrevQueuedRequests;
+ virtual void QueuedRequestCountChanged();
+ };
- None of the internal DMA framework mutexes is being held by the PIL when
- calling this function.
+ void TFooDmaChannel::QueuedRequestCountChanged()
+ {
+ Kern::MutexWait(*iDmaMutex);
+ const TInt queued_now = __e32_atomic_load_acq32(&iQueuedRequests);
+ if ((queued_now > 0) && (iPrevQueuedRequests == 0))
+ {
+ IncreasePowerCount(); // Base port specific
+ }
+ else if ((queued_now == 0) && (iPrevQueuedRequests > 0))
+ {
+ DecreasePowerCount(); // Base port specific
+ }
+ iPrevQueuedRequests = queued_now;
+ Kern::MutexSignal(*iDmaMutex);
+ }
- @see iQueuedRequests
- */
+ @endcode
+
+ @see iQueuedRequests
+ */
virtual void QueuedRequestCountChanged();
#if defined(__CPU_ARM) && !defined(__EABI__)
inline virtual ~TDmaChannel() {} // kill really annoying warning