diff -r 000000000000 -r a41df078684a kernel/eka/nkernsmp/arm/ncirq.cia --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/nkernsmp/arm/ncirq.cia Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,240 @@ +// Copyright (c) 2008-2009 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: +// e32\nkernsmp\arm\ncirq.cia +// +// + +/** + @file + @internalTechnology +*/ + +#include "nk_priv.h" +#include "nk_plat.h" +#include +#include +#include +#include +#include + +// +// Atomically increment run count provided ECount set or count <2. +// If originally zero, atomically set CPU field +// Wait for EWait to be clear +// Return state of iIState immediately before increment +// +__NAKED__ TUint32 NIrq::EnterIsr() + { + GET_RWNO_TID(,r12); + asm("add r3, r0, #%a0" : : "i" _FOFF(NIrq,iIState)); + asm("ldr r12, [r12, #%a0]" : : "i" _FOFF(TSubScheduler,iCpuNum)); + + asm("1: "); + LDREX(0,3); + asm("mov r1, r0 "); + asm("cmp r0, #0x10000 "); // run count >= 1 ? + asm("biclo r1, r1, #0xff00 "); // if not, update CPU + asm("orrlo r1, r1, r12, lsl #8 "); + asm("add r1, r1, #0x10000 "); // increment run count + asm("cmp r1, #0x20000 "); // >= 2 ? + asm("bhs 3f "); + asm("2: "); + STREX(2,1,3); + asm("cmp r2, #0 "); + asm("bne 1b "); + + asm("4: "); + __DATA_MEMORY_BARRIER__(r2); + asm("tst r1, #%a0" : : "i" (NIrq::EWait)); + asm("bne 5f "); + __JUMP(,lr); + + asm("3: "); + asm("tst r1, #%a0" : : "i" (NIrq::ECount|NIrq::ERaw)); + asm("bne 2b "); + asm("mov r2, #0 "); + asm("b 4b "); + + asm("5: "); + ARM_WFE; + asm("ldr r1, [r3] "); + asm("b 4b "); + } + +// +// Atomically decrement run count +// Return TRUE if run count nonzero after decrement +// +__NAKED__ TBool NIrq::IsrDone() + { + asm("add r3, r0, #%a0" : : "i" _FOFF(NIrq,iIState)); + __DATA_MEMORY_BARRIER_Z__(r2); + + asm("1: "); + LDREX(0,3); + asm("subs r1, r0, #0x10000 "); + STREX(2,1,3); + asm("cmp r2, #0 "); + asm("bne 1b "); + asm("mov r0, r1, lsr #16 "); // r0 = new run count = TRUE if nonzero + __JUMP(,lr); + } + +// +// Wait (allowing interrupts and preemption) until run count = 0 and EWait clear +// Then atomically set EWait and return with interrupts disabled +// +__NAKED__ void NIrq::Wait() + { + asm("add r3, r0, #%a0" : : "i" _FOFF(NIrq,iIState)); + + asm("0: "); + __ASM_CLI(); + + asm("1: "); + LDREX(0,3); + asm("mov r1, r0, ror #1 "); // bit 31 = wait, bits 15-30 = run count + asm("cmp r1, #0x8000 "); // run count and EWait both zero? + asm("bcs 2f "); // if not, must wait + asm("orr r1, r0, #1 "); // else try to set EWait + STREX(2,1,3); + asm("cmp r2, #0 "); + asm("bne 1b "); + __DATA_MEMORY_BARRIER__(r2); + __JUMP(,lr); // success - return with interrupts disabled + + // spin, allowing interrupts, while we wait for run count and EWait both zero + asm("2: "); + __ASM_STI(); + asm("nop "); + ARM_WFE; + asm("nop "); + asm("b 0b "); + } + +// +// Atomically clear EWait and reenable interrupts +// +__NAKED__ void NIrq::Done() + { + asm("add r3, r0, #%a0" : : "i" _FOFF(NIrq,iIState)); + __DATA_MEMORY_BARRIER_Z__(r2); + + asm("1: "); + LDREX(0,3); + asm("bic r0, r0, #1 "); // clear EWait + STREX(2,0,3); + asm("cmp r2, #0 "); + asm("bne 1b "); + __DATA_SYNC_BARRIER__(r2); // ensure completion before SEV + ARM_SEV; // kick any waiting processors + __ASM_STI(); // interrupts back on + __JUMP(,lr); + } + + + +// +// atomic { if !EUnbind && !ENotReady clear EDisable } +// Return the initial value of iHState +// +__NAKED__ TUint32 NIrqHandler::DoSetEnabled() + { + asm("add r3, r0, #%a0" : : "i" _FOFF(NIrqHandler,iHState)); + __DATA_MEMORY_BARRIER_Z__(r2); + + asm("1: "); + LDREX(0,3); + asm("tst r0, #%a0" : : "i" (NIrqHandler::EUnbind|NIrqHandler::ENotReady)); + asm("bne 2f "); // if EUnbind or ENotReady, finished + asm("bic r1, r0, #%a0" : : "i" (NIrqHandler::EDisable|NIrqHandler::EBind)); + STREX(2,1,3); + asm("cmp r2, #0 "); + asm("bne 1b "); + + asm("2: "); + __DATA_MEMORY_BARRIER__(r2); + __JUMP(,lr); + } + +// +// Atomically increment run count by aCount if ECount set or run count initially zero. +// If !EDisable and !EUnbind set EActive +// Return initial iHState +// +__NAKED__ TUint32 NIrqHandler::DoActivate(TInt /*aCount*/) + { + asm("add r3, r0, #%a0" : : "i" _FOFF(NIrqHandler,iHState)); + + asm("1: "); + LDREX(0,3); + asm("mov r2, r0 "); + asm("cmp r0, #0x10000 "); + asm("blo 2f "); // if run count initially zero, skip + asm("tst r0, #%a0" : : "i" (NIrqHandler::ECount)); + asm("beq 3f "); // else if !ECount, don't increment + asm("2: "); + asm("add r2, r2, r1, lsl #16 "); // add aCount to run count + asm("3: "); + asm("tst r2, #%a0" : : "i" (NIrqHandler::EUnbind|NIrqHandler::EDisable)); + asm("orreq r2, r2, #%a0" : : "i" (NIrqHandler::EActive)); // if !EUnbind && !EDisable, set EActive + STREX(12,2,3); + asm("cmp r12, #0 "); + asm("bne 1b "); + __DATA_MEMORY_BARRIER__(r12); + __JUMP(,lr); + } + +// +// Decrement run count +// Return initial iHState +// +__NAKED__ TUint32 NIrqHandler::EventBegin() + { + asm("add r3, r0, #%a0" : : "i" _FOFF(NIrqHandler,iHState)); + + asm("1: "); + LDREX(0,3); + asm("sub r2, r0, #0x10000 "); + STREX(12,2,3); + asm("cmp r12, #0 "); + asm("bne 1b "); + __DATA_MEMORY_BARRIER__(r12); + __JUMP(,lr); + } + +// +// If count is zero or EDisable or EUnbind +// are set, clear EActive. +// Return initial iHState, except for new EActive bit +// +__NAKED__ TUint32 NIrqHandler::EventDone() + { + asm("add r3, r0, #%a0" : : "i" _FOFF(NIrqHandler,iHState)); + __DATA_MEMORY_BARRIER_Z__(r12); + + asm("1: "); + LDREX(0,3); + asm("mov r2, r0 "); + asm("cmp r0, #0x10000 "); // run count zero ? + asm("tsths r2, #%a0" : : "i" (NIrqHandler::EUnbind|NIrqHandler::EDisable)); // if so, test EUnbind and EDisable + asm("bicne r2, r2, #%a0" : : "i" (NIrqHandler::EActive)); // if runcount==0 or EUnbind or EDisable set, clear EActive + STREX(12,2,3); + asm("cmp r12, #0 "); + asm("bne 1b "); + asm("tst r2, #%a0" : : "i" (NIrqHandler::EActive)); // EActive now clear in new value ? + asm("biceq r0, r0, #%a0" : : "i" (NIrqHandler::EActive)); // if so, clear it in return value + __JUMP(,lr); + } +