kernel/eka/drivers/dma/dma2_pil.cpp
branchRCL_3
changeset 87 2f92ad2dc5db
parent 36 538db54a451d
equal deleted inserted replaced
81:e7d2d738d3c2 87:2f92ad2dc5db
     1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
     1 // Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
  1953 			Flash();
  1953 			Flash();
  1954 			}
  1954 			}
  1955 		stop = __e32_atomic_load_acq32(&iIsrDfc) & (TUint32)KCancelFlagMask;
  1955 		stop = __e32_atomic_load_acq32(&iIsrDfc) & (TUint32)KCancelFlagMask;
  1956 		}
  1956 		}
  1957 
  1957 
  1958 	// Some interrupts may be missed (double-buffer and scatter-gather
       
  1959 	// controllers only) if two or more transfers complete while interrupts are
       
  1960 	// disabled in the CPU. If this happens, the framework will go out of sync
       
  1961 	// and leave some orphaned requests in the queue.
       
  1962 	//
       
  1963 	// To ensure correctness we handle this case here by checking that the request
       
  1964 	// queue is empty when all transfers have completed and, if not, cleaning up
       
  1965 	// and notifying the client of the completion of the orphaned requests.
       
  1966 	//
       
  1967 	// Note that if some interrupts are missed and the controller raises an
       
  1968 	// error while transferring a subsequent fragment, the error will be reported
       
  1969 	// on a fragment which was successfully completed.  There is no easy solution
       
  1970 	// to this problem, but this is okay as the only possible action following a
       
  1971 	// failure is to flush the whole queue.
       
  1972 	if (stop)
  1958 	if (stop)
  1973 		{
  1959 		{
  1974 		// If another thread set the cancel flag, it should have
  1960 		// If another thread set the cancel flag, it should have
  1975 		// cleaned up the request queue
  1961 		// cleaned up the request queue
  1976 		__DMA_ASSERTD(IsQueueEmpty());
  1962 		__DMA_ASSERTD(IsQueueEmpty());
  1986 
  1972 
  1987 		Signal();
  1973 		Signal();
  1988 
  1974 
  1989 		// release threads doing CancelAll()
  1975 		// release threads doing CancelAll()
  1990 		waiters->Signal();
  1976 		waiters->Signal();
  1991 		}
       
  1992 	else if (!error && !iReqQ.IsEmpty() && iController->IsIdle(*this))
       
  1993 		{
       
  1994 #ifdef __SMP__
       
  1995 		// On an SMP system we must call stop transfer, it will block until
       
  1996 		// any ISRs have completed so that the system does not spuriously
       
  1997 		// attempt to recover from a missed interrupt.
       
  1998 		//
       
  1999 		// On an SMP system it is possible for the code here to execute
       
  2000 		// concurrently with the DMA ISR. It is therefore possible that at this
       
  2001 		// point the previous transfer has already completed (so that IsIdle
       
  2002 		// reports true), but that the ISR has not yet queued a DFC. Therefore
       
  2003 		// we must wait for the ISR to complete.
       
  2004 		//
       
  2005 		// StopTransfer should have no other side effect, given that the
       
  2006 		// channel is already idle.
       
  2007 		iController->StopTransfer(*this); // should block till ISR completion
       
  2008 #endif
       
  2009 
       
  2010 		const TBool cleanup = !iDfc.Queued();
       
  2011 		if(cleanup)
       
  2012 			{
       
  2013 			__KTRACE_OPT(KDMA, Kern::Printf("Missed interrupt(s) - draining request queue"));
       
  2014 			ResetStateMachine();
       
  2015 
       
  2016 			// Move orphaned requests to temporary queue so channel queue can
       
  2017 			// accept new requests.
       
  2018 			SDblQue q;
       
  2019 			q.MoveFrom(&iReqQ);
       
  2020 
       
  2021 			SDblQueLink* pL;
       
  2022 			while ((pL = q.GetFirst()) != NULL)
       
  2023 				{
       
  2024 				DDmaRequest* const pR = _LOFF(pL, DDmaRequest, iLink);
       
  2025 				__KTRACE_OPT(KDMA, Kern::Printf("Removing request from queue and notifying client"));
       
  2026 				pR->OnDeque();
       
  2027 				// Old style callback
       
  2028 				DDmaRequest::TCallback const cb = pR->iCb;
       
  2029 				if (cb)
       
  2030 					{
       
  2031 					TAny* const arg = pR->iCbArg;
       
  2032 					Signal();
       
  2033 					(*cb)(DDmaRequest::EOk, arg);
       
  2034 					Wait();
       
  2035 					}
       
  2036 				else
       
  2037 					{
       
  2038 					// New style callback
       
  2039 					TDmaCallback const ncb = pR->iDmaCb;
       
  2040 					if (ncb)
       
  2041 						{
       
  2042 						TAny* const arg = pR->iDmaCbArg;
       
  2043 						Signal();
       
  2044 						(*ncb)(EDmaCallbackRequestCompletion, EDmaResultOK, arg, NULL);
       
  2045 						Wait();
       
  2046 						}
       
  2047 					}
       
  2048 				}
       
  2049 			}
       
  2050 		Signal();
       
  2051 		}
  1977 		}
  2052 	else
  1978 	else
  2053 		Signal();
  1979 		Signal();
  2054 
  1980 
  2055 	__DMA_INVARIANT();
  1981 	__DMA_INVARIANT();