diff -r 2bb754abd467 -r 0ffb4e86fcc9 kernel/eka/include/drivers/dma.h --- 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