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(); |