diff -r c1f20ce4abcf -r 3e88ff8f41d5 kernel/eka/drivers/power/smppower/idlehelper.cia --- a/kernel/eka/drivers/power/smppower/idlehelper.cia Tue Aug 31 16:34:26 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,304 +0,0 @@ -// Copyright (c) 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: -// -// Description: -// os\kernelhwsrv\kernel\eka\drivers\power\smpidlehelper.cpp -// Impelentation of helper classes required to implement CPU idle -// functionality in a SMP BSP. - -/** - @file - @prototype -*/ - - - -#ifdef __SMP__ - - -#include - - -#ifndef DISABLE_TRACE - -extern "C" void btrace_printfn(const TAny *aPtr,const TInt regNum) - { - PMBTRACE4(KPrintReg,regNum,aPtr); - } - -extern "C" void btrace_printfnId(const TAny *aPtr,const TInt regNum, TUint aId) - { - PMBTRACE8(KPrintReg,0xffu,regNum,aPtr); - } - -#define PRINTREG(Rn) \ - asm("stmfd sp!,{r0-r12,lr}"); \ - asm("mov r0,r"#Rn); \ - asm("mov r1,#"#Rn); \ - asm("bl btrace_printfn"); \ - asm("ldmfd sp!,{r0-r12,lr}"); - -#define PRINTREGID(Rn,n) \ - asm("stmfd sp!,{r0-r12,lr}"); \ - asm("mov r0,r"#Rn); \ - asm("mov r1,#"#Rn); \ - asm("mov r2,#"#n); \ - asm("bl btrace_printfnId"); \ - asm("ldmfd sp!,{r0-r12,lr}"); - - -#else -#define PRINTREG(Rn) -#define PRINTREGID(Rn,n) -#endif - - -/** - Atomically does the following: - sets the current cpu idle mask bit to indicate current core wants to idle - if all enaged cores have set their bit the flag KGlobalIdleFlag is also - orred into the idle mask to indicate all cores are going down. In this case - the function returned true. False otherwise - - aCMask- Bit mask with only current CPU bit set - Normal Usage:use in idle handler before waiting for all cores down IPI - - @pre - */ - -__NAKED__ TBool TIdleSupport::SetLocalAndCheckSetGlobalIdle(TUint32 /*aCpuMask*/) - { - asm("ldr r1,__iAllEngagedCpusMask"); //r1 = address of iAllEngagedCpusMask - asm("ldr r2, [r1]"); //r2 = iAllEngagedCpusMask - asm("add r1,r1,#4"); //r1 = address of iIdlingCpus - __DATA_MEMORY_BARRIER_Z__(r12); - asm("1: "); - LDREX(3,1); // r3 = iIdlingCpus - asm("orr r3,r0,r3"); // orr in mask for this CPU - asm("cmp r3,r2"); // compare to iAllEngagedCpusMask - asm("orreq r3,r3,#%a0" : : "i" ((TInt)TIdleSupport::KGlobalIdleFlag)); // if equal orr in KGlobalIdleFlag - STREX(12,3,1); - asm("cmp r12, #0 "); // - asm("bne 1b "); // write didn't succeed try again - __DATA_MEMORY_BARRIER__(r12); - asm("and r0,r3,#%a0" : : "i" ((TInt)TIdleSupport::KGlobalIdleFlag)); - __JUMP(,lr); - asm("__iAllEngagedCpusMask:"); - asm(".word %a0" : : "i" ((TInt)&TIdleSupport::iAllEngagedCpusMask));// - } - -/** - -Wait for all CPUs to reach the sync point. A CPU will only exit this function when all other CPUs -have reached it. - -Works like this: - -cpuMask = 1 << NKern::CurrentCpu() -BEGIN_ATOMIC - stage = iStageAndCPUWaitingMask >> 16 - waitingCpus = iStageAndCPUWaitingMask&iAllCpusMask - oldstage = stage; - if (waitingCpus == iAllCpusMask) // we synched already and this is new - waitingCpus = 0; - waitingCpus |= cpuMask - if (waitingCpus == iAllCpusMask) stage++ - iStageAndCPUWaitingMask = (stage << 16) | waitingCpus -END_ATOMIC -FOREVER - if (oldstage!=stage) return - stage = iStageAndCPUWaitingMask >> 16 // reread stage -END_FOREVER - -*/ -__NAKED__ void TSyncPoint::DoSW(TUint32 /*aCpuMask*/) - { - asm("stmfd sp!, {r4-r5,lr} "); - asm("add r0,r0,#%a0" : : "i" _FOFF(TSyncPointBase, iStageAndCPUWaitingMask)); // skip vt - asm("ldr r4,[r0,#4]"); - asm("ldr r4,[r4]"); - __DATA_MEMORY_BARRIER_Z__(r12); // - asm("1: "); - LDREX(2,0); // r2 = iStageAndCPUWaitingMask, r4 = iAllEnagedCpusMask - asm("mov r5,r2,lsr #16"); // r5 has old staging value - asm("and r2,r2,r4"); // r2 has currently waiting cpus - asm("cmp r2,r4"); // if r2 == r4 then we previously have had all cpus synched - asm("moveq r2,#0"); // reset - asm("orr r2, r2, r1"); // orr mask for this CPU - asm("mov r3,r5"); // r3 will have new stage - asm("cmp r2,r4"); // if r2 == r4 then all cpus have set - asm("addeq r3,r3,#1"); // increment new stage count - asm("orr r2,r2,r3, lsl #16"); - STREX(12,2,0); // try to atomically iStageAndCPUWaitingMask - asm("cmp r12, #0 "); - asm("bne 1b "); // write didn't succeed try again - __DATA_MEMORY_BARRIER__(r12); // ensure that's written -#ifdef SYNCPOINT_WFE - asm("ands r2,r2,r4"); - asm("cmp r2,r4"); // if r2 == r4 then all cpus have set - ARM_SEVcc(CC_EQ); -#endif - asm("2: "); - asm("cmp r3,r5"); // all (old stage does not equal new stage) - asm("ldmnefd sp!, {r4-r5,pc}"); // yup return -#ifdef SYNCPOINT_WFE - __DATA_MEMORY_BARRIER__(r12); - ARM_WFE; -#endif - asm("ldr r2,[r0]"); // otherwise re read iWaitingCpusMask into r5 - __DATA_MEMORY_BARRIER__(r12); // ensure read is observed - asm("mov r3,r2,lsr #16"); // re-read new stage - asm("b 2b"); // loop back - } - -/** - -Wait for all CPUs to reach the sync point. A CPU will only exit this function when all other CPUs -have reached it or if another CPU has called the Break function. An attempt to wait on a broken -syncpoint will return immediately. - -Works like this: - -cpuMask = 1 << NKern::CurrentCpu() -BEGIN_ATOMIC - waitingCpus = iStageAndCPUWaitingMask&iAllEnagedCpusMask - if (iStageAndCPUWaitingMask & 0x80000000) // sync point is broken - END_ATOMIC and return - - waitingCpus |= cpuMask - if (waitingCpus == iAllEnagedCpusMask) waitingCpus |= 0x80000000 - iStageAndCPUWaitingMask = waitingCpus -END_ATOMIC -FOREVER - if (iStageAndCPUWaitingMask&0x80000000) break -END_FOREVER - -*/ -__NAKED__ void TBreakableSyncPoint::DoSW(TUint32 /*aCpuMask*/) - { - asm("stmfd sp!, {r4,lr} "); - asm("add r0,r0,#%a0" : : "i" _FOFF(TSyncPointBase, iStageAndCPUWaitingMask)); // skip vt - asm("ldr r4,[r0,#4]"); - asm("ldr r4,[r4]"); - __DATA_MEMORY_BARRIER_Z__(r12); // - asm("1: "); - LDREX(2,0); // r2 = iStageAndCPUWaitingMask, r4 = iAllEnagedCpusMask - asm("ands r3,r2,#0x80000000"); // - asm("bne 3f"); // sync point broken so return - asm("and r2,r2,r4"); // r2 has currently waiting cpus - asm("orr r2, r2, r1"); // orr mask for this CPU - asm("cmp r2,r4"); // if r2 == r4 then all cpus have set - asm("orreq r2,r2,#0x80000000"); // set MSB - STREX(12,2,0); // try to atomically iStageAndCPUWaitingMask - asm("cmp r12, #0 "); - asm("bne 1b "); // write didn't succeed try again - __DATA_MEMORY_BARRIER__(r12); // ensure that's written -#ifdef SYNCPOINT_WFE - asm("ands r3,r2,#0x80000000"); // MSB set? - ARM_SEVcc(CC_NE); -#endif - asm("2: "); - asm("ands r3,r2,#0x80000000"); // MSB set? - asm("ldmnefd sp!, {r4,pc}"); // yup return -#ifdef SYNCPOINT_WFE - __DATA_MEMORY_BARRIER__(r12); - ARM_WFE; -#endif - asm("ldr r2,[r0]"); // otherwise re read iWaitingCpusMask into r5 - //__DATA_MEMORY_BARRIER_Z__(r12); // ensure read is observed - asm("b 2b"); // loop back - asm("3:"); - CLREX; -#ifdef SYNCPOINT_WFE - __DATA_MEMORY_BARRIER__(r12); // ensure that's written - ARM_SEV; -#endif - asm("ldmfd sp!, {r4,pc}"); // yup return - } - - -#ifdef PROPER_WFI -__NAKED__ void TIdleSupport::DoWFI() - { - __DATA_SYNC_BARRIER_Z__(r12); // generally good idea to a barrier before WFI - ARM_WFI; - __JUMP(,lr); - } -#else -void TIdleSupport::DoWFI() - { - TInt c=NKern::CurrentCpu(); - FOREVER - { - TInt isr = Pending(); - if (isr!=1023) - { - BTRACE0(KIsrPendingCat,isr&0xff); - break; - } - } - } -#endif - -__NAKED__ void TIdleSupport::DoIdleIPI(TUint32 /*aMask*/) - { - //r0 = cpu mask - asm("ldr r2,__EnagedCpusMask"); // only IPI enaged cores r2 has enaged core mask addr - asm("ldr r2,[r2]"); - asm("and r0,r0,r2"); // and out retired cores - asm("ldr r1,__KGICAddr");//r1 = address off iGlobalIntDistAddress - asm("ldr r1, [r1]");//r1 = address of Hw GIC interrupt dispatcher base - __DATA_SYNC_BARRIER_Z__(r12); // need DSB before sending any IPI - asm("movs r0, r0, lsl #16 "); // CPU mask into bits 16-23 - any bits set in aMask? - asm("orrne r0, r0, #%a0" : : "i" ((TInt) IDLE_WAKEUP_IPI_VECTOR)); - asm("strne r0, [r1, #%a0]" : : "i" _FOFF(GicDistributor, iSoftIrq)); // trigger IPIs if any - __JUMP(,lr); - asm("__KGICAddr:"); - asm(".word %a0" : : "i" ((TInt)&TIdleSupport::iGlobalIntDistAddress)); - asm("__EnagedCpusMask:"); - asm(".word %a0" : : "i" ((TInt)&TIdleSupport::iAllEngagedCpusMask)); - } - -#ifdef _DEBUG -__NAKED__ TInt TIdleSupport::DoClearIdleIPI() -#else -__NAKED__ void TIdleSupport::ClearIdleIPI() -#endif - { - __DATA_SYNC_BARRIER_Z__(r12); // DSB - asm("ldr r1,__KCPUIFAddr");//r1 = address of iBaseIntIfAddress - asm("ldr r1, [r1]");//r1 = address of Hw GIC CPU interrupt interface base address - asm("ldr r0,[r1, #%a0]" : : "i" _FOFF(GicCpuIfc, iAck)); - // asm("mov r0,#%a0" : : "i" ((TInt) IDLE_WAKEUP_IPI_VECTOR)); // has to be! - asm("str r0, [r1, #%a0]" : : "i" _FOFF(GicCpuIfc, iEoi)); - __JUMP(,lr); - asm("__KCPUIFAddr:"); - asm(".word %a0" : : "i" ((TInt)&TIdleSupport::iBaseIntIfAddress));// CPU interrupt interface base address - } - -#ifndef _DEBUG -TInt TIdleSupport::DoClearIdleIPI() - { - return 0; - } -#endif - -__NAKED__ TInt TIdleSupport::IntPending() - { - asm("ldr r1,__KCPUIFAddr");//r1 = address of iBaseIntIfAddress - asm("ldr r1, [r1]");//r1 = address of Hw GIC CPU interrupt interface base address - asm("ldr r0, [r1, #%a0]" : : "i" _FOFF(GicCpuIfc, iHighestPending)); - __JUMP(,lr); - } - - -#endif // ifdef __SMP__