diff -r 000000000000 -r a41df078684a kernel/eka/nkernsmp/arm/ncirq.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/nkernsmp/arm/ncirq.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,480 @@ +// 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.cpp +// +// + +/** + @file + @internalTechnology +*/ + +#include "nk_priv.h" +#include "nk_plat.h" +#include +#include +#include +#include +#include + +#ifdef _DEBUG +#define DMEMDUMP(base,size) DbgMemDump((TLinAddr)base,size) +void DbgMemDump(TLinAddr aBase, TInt aSize) + { + TInt off; + const TUint8* p=(const TUint8*)aBase; + NKern::Lock(); + for (off=0; off>5] = mask; + arm_dsb(); + } + +void ArmGic::Disable(TInt aIndex) + { + TUint32 mask = 1u << (aIndex&31); + GIC_DIST.iEnableClear[aIndex>>5] = mask; + arm_dsb(); + } + +TBool ArmGic::IsEnabled(TInt aIndex) + { + TUint32 mask = 1u << (aIndex&31); + return GIC_DIST.iEnableSet[aIndex>>5] & mask; + } + +void ArmGic::SetPending(TInt aIndex) + { + TUint32 mask = 1u << (aIndex&31); + GIC_DIST.iPendingSet[aIndex>>5] = mask; + arm_dsb(); + } + +void ArmGic::ClearPending(TInt aIndex) + { + TUint32 mask = 1u << (aIndex&31); + GIC_DIST.iPendingClear[aIndex>>5] = mask; + arm_dsb(); + } + +TBool ArmGic::IsPending(TInt aIndex) + { + TUint32 mask = 1u << (aIndex&31); + return GIC_DIST.iPendingSet[aIndex>>5] & mask; + } + +TBool ArmGic::IsActive(TInt aIndex) + { + TUint32 mask = 1u << (aIndex&31); + return GIC_DIST.iActive[aIndex>>5] & mask; + } + +TUint32 ArmGic::Dest(TInt aIndex) + { + TUint32 reg = GIC_DIST.iTarget[aIndex>>2]; + reg >>= ((aIndex&3)<<3); + reg &= 0xff; + return reg; + } + +TUint32 ArmGic::ModifyDest(TInt aIndex, TUint32 aClear, TUint32 aSet) + { + aClear &= 0xff; + aSet &= 0xff; + TInt shift = (aIndex&3)<<3; + aClear <<= shift; + aSet <<= shift; + volatile TUint32& reg = GIC_DIST.iTarget[aIndex>>2]; + TInt irq = __SPIN_LOCK_IRQSAVE(ArmGicLock); + TUint32 old = reg; + reg = (old &~ aClear) | aSet; + arm_dsb(); + __SPIN_UNLOCK_IRQRESTORE(ArmGicLock, irq); + old >>= shift; + return old & 0xff; + } + +TUint32 ArmGic::Config(TInt aIndex) + { + TInt shift = (aIndex&15)<<1; + TUint32 x = GIC_DIST.iConfig[aIndex>>4]; + x >>= shift; + return x & 3; + } + +TUint32 ArmGic::ModifyConfig(TInt aIndex, TUint32 aClear, TUint32 aSet) + { + aClear &= 3; + aSet &= 3; + TInt shift = (aIndex&15)<<1; + aClear <<= shift; + aSet <<= shift; + volatile TUint32& reg = GIC_DIST.iConfig[aIndex>>4]; + TInt irq = __SPIN_LOCK_IRQSAVE(ArmGicLock); + TUint32 old = reg; + reg = (old &~ aClear) | aSet; + arm_dsb(); + __SPIN_UNLOCK_IRQRESTORE(ArmGicLock, irq); + old >>= shift; + return old & 3; + } + +TBool ArmGic::SetNonSecure(TInt aIndex, TBool aNonSecure) + { + TUint32 mask = 1u << (aIndex & 31); + volatile TUint32& reg = GIC_DIST.iIntSec[aIndex>>5]; + TInt irq = __SPIN_LOCK_IRQSAVE(ArmGicLock); + TUint32 old = reg; + reg = aNonSecure ? (old | mask) : (old &~ mask); + arm_dsb(); + __SPIN_UNLOCK_IRQRESTORE(ArmGicLock, irq); + return old & mask; + } + +TUint32 ArmGic::Priority(TInt aIndex) + { + TInt shift = (aIndex&3)<<3; + TUint32 x = GIC_DIST.iPriority[aIndex>>2]; + x >>= shift; + return x & 0xff; + } + +TUint32 ArmGic::SetPriority(TInt aIndex, TUint32 aPri) + { + aPri &= 0xff; + TInt shift = (aIndex&3)<<3; + TUint32 clear = 0xffu << shift; + aPri <<= shift; + volatile TUint32& reg = GIC_DIST.iPriority[aIndex>>2]; + TInt irq = __SPIN_LOCK_IRQSAVE(ArmGicLock); + TUint32 old = reg; + reg = (old &~ clear) | aPri; + arm_dsb(); + __SPIN_UNLOCK_IRQRESTORE(ArmGicLock, irq); + old >>= shift; + return old & 0xff; + } + +void ArmGic::Dump() + { +#ifdef KBOOT + __KTRACE_OPT(KBOOT,DEBUGPRINT("GIC iCtrl=%08x iType=%08x", GIC_DIST.iCtrl, GIC_DIST.iType)); + TInt n = ArmGic::NumLines; + TInt i; + for (i=0; iiEoiFn) + (*iX->iEoiFn)(this); + else + { + GIC_CPU_IFC.iEoi = iVector; + +#if defined(SMP_CRAZY_INTERRUPTS) && !defined(__STANDALONE_NANOKERNEL__) + // change the target CPU for the next Interrupt + if ((TInt)TheSuperPage().KernelConfigFlags() & EKernelConfigSMPCrazyInterrupts) + { + TInt cpu = NKern::CurrentCpu() + 1; + if(cpu >= NKern::NumberOfCpus()) + cpu = 0; + ArmGic::ModifyDest(iVector, 0xffu, 1u << cpu); + } + else + arm_dsb(); + +#else + arm_dsb(); +#endif + } + } + +void NIrq::HwEnable() + { + if (iX && iX->iEnableFn) + (*iX->iEnableFn)(this); + else + { + ArmGic::Enable(iVector); + } + } + +void NIrq::HwDisable() + { + if (iX && iX->iDisableFn) + (*iX->iDisableFn)(this); + else + { + ArmGic::Disable(iVector); + } + } + +void NIrq::HwSetCpu(TInt aCpu) + { + if (iX && iX->iSetCpuFn) + (*iX->iSetCpuFn)(this, 1u<iSetCpuFn) + (*iX->iSetCpuFn)(this, aMask); + else + { + ArmGic::ModifyDest(iVector, 0xffu, aMask); + } + } + +void NIrq::HwInit() + { + if (iX && iX->iInitFn) + (*iX->iInitFn)(this); + else + { + __KTRACE_OPT(KBOOT,DEBUGPRINT("NIrq %02x HwInit", iIndex)); + TUint32 clear = E_GicDistICfgEdge; + TUint32 set = 0; + if (!(iStaticFlags & ELevel)) + set = E_GicDistICfgEdge; + ArmGic::ModifyConfig(iVector, clear, set); + } + } + +TBool NIrq::HwPending() + { + if (iX && iX->iPendingFn) + return (*iX->iPendingFn)(this); + return ArmGic::IsPending(iVector) || ArmGic::IsActive(iVector); + } + +void NIrq::HwWaitCpus() + { + if (iX && iX->iWaitFn) + (*iX->iWaitFn)(this); + } + +void NIrq::HwInit0() + { + __KTRACE_OPT(KBOOT, DEBUGPRINT("NIrq::HwInit0")); + + // Need to set up addresses of GIC_DIST, GIC_CPU_IFC, SCU and LOCAL_TIMER + + GicDistributor& D = GIC_DIST; + GicCpuIfc& C = GIC_CPU_IFC; + D.iCtrl = 0; + C.iCtrl = 0; + arm_dsb(); + TUint32 type = D.iType; + __KTRACE_OPT(KBOOT, DEBUGPRINT("GIC iType = %08x", type)); + ArmGic::LSPI = (type & E_GicDistType_LSPIMask) >> E_GicDistType_LSPIShift; + ArmGic::Domains = (type & E_GicDistType_Domains) ? 2 : 1; + ArmGic::NumCpus = ((type & E_GicDistType_CPUNMask) >> E_GicDistType_CPUNShift) + 1; + ArmGic::NumLines = ((type & E_GicDistType_ITMask) + 1) << 5; + __KTRACE_OPT(KBOOT, DEBUGPRINT("GIC LSPI=%d Domains=%d NumCpus=%d NumLines=%d", + ArmGic::LSPI, ArmGic::Domains, ArmGic::NumCpus, ArmGic::NumLines)); + TInt i; + for (i=0; i<32; ++i) + D.iEnableClear[i] = 0xffffffffu; // disable all interrupts + arm_dsb(); + for (i=0; i<32; ++i) + D.iPendingClear[i] = 0xffffffffu; // clear any pending interrupts + arm_dsb(); + D.iPriority[0] = 0xffffffffu; + ArmGic::PriMask = D.iPriority[0] & 0xffu; + ArmGic::PriSpc = (~ArmGic::PriMask + 1) & 0xffu; + ArmGic::MinPri = ArmGic::PriMask - ArmGic::PriSpc; + __KTRACE_OPT(KBOOT, DEBUGPRINT("PriMask=%02x PriSpc=%02x MinPri=%02x", ArmGic::PriMask, ArmGic::PriSpc, ArmGic::MinPri)); + TUint32 x = ArmGic::MinPri; + x |= (x<<8); + x |= (x<<16); + for (i=0; i<256; ++i) + D.iPriority[i] = x; // set all interrupts to minimum active priority + x = 0x01010101u; + for (i=0; i<256; ++i) + D.iTarget[i] = x; // set all interrupts to target this CPU + x = 0xAAAAAAAAu; // config value for SW interrupts (rising edge, N-N) + D.iConfig[0] = x; // set config for 0-15 + x = 0x28000000u; // 31=0b00, 30=29=0b10 + D.iConfig[1] = x; // set config for 16-31 + x = 0xAAAAAAAAu; // config value for SW interrupts (rising edge, N-N) + for (i=2; i<64; ++i) + D.iConfig[i] = x; // set default value for other interrupts + arm_dsb(); + ArmGic::Dump(); + } + +void NIrq::HwInit1() + { + __KTRACE_OPT(KBOOT, DEBUGPRINT("NIrq::HwInit1")); + + // elevate priority of CRASH_IPI to highest level + ArmGic::SetPriority(CRASH_IPI_VECTOR, 0); + + GicDistributor& D = GIC_DIST; + GicCpuIfc& C = GIC_CPU_IFC; + C.iCtrl = 0; + C.iPriMask = ArmGic::PriMask; // unmask all interrupts + C.iBinaryPoint = 0; + arm_dsb(); + C.iCtrl = E_GicDistCtrl_Enable; // enable this CPU's interrupt controller interface + arm_dsb(); + D.iCtrl = E_GicDistCtrl_Enable; // enable the global interrupt distributor + arm_dsb(); + + // Enable timeslice timer interrupt + ArmLocalTimer& T = LOCAL_TIMER; + T.iTimerCtrl = 0; + T.iTimerIntStatus = E_ArmTmrIntStatus_Event; + ArmGic::ClearPending(TIMESLICE_VECTOR); + arm_dsb(); + ArmGic::Enable(TIMESLICE_VECTOR); + arm_dsb(); + T.iTimerLoad = KMaxTUint32; // timer wraps to 0xffffffff after reaching 0 + arm_dsb(); + T.iTimerCount = (TUint32)KMaxTInt32; // timer starts at 0x7fffffff (initial thread doesn't timeslice) + arm_dsb(); + + ArmGic::DumpCpuIfc(); + } + +void NIrq::HwInit2AP() + { + __KTRACE_OPT(KBOOT, DEBUGPRINT("NIrq::HwInit2AP")); + + // Must set up interrupts 0-31 separately for each CPU + GicDistributor& D = GIC_DIST; + TInt i; + TUint32 x = ArmGic::MinPri; + x |= (x<<8); + x |= (x<<16); + for (i=0; i<32; ++i) + D.iPriority[i] = x; // set all interrupts to minimum active priority + x = 0xAAAAAAAAu; // config value for SW interrupts (rising edge, N-N) + D.iConfig[0] = x; // set config for 0-15 + x = 0x28000000u; // 31=0b00, 30=29=0b10 + D.iConfig[1] = x; // set config for 16-31 + arm_dsb(); + ArmGic::Dump(); + + // elevate priority of CRASH_IPI to highest level + ArmGic::SetPriority(CRASH_IPI_VECTOR, 0); + + GicCpuIfc& C = GIC_CPU_IFC; + C.iCtrl = 0; + C.iPriMask = ArmGic::PriMask; // unmask all interrupts + C.iBinaryPoint = 0; + arm_dsb(); + C.iCtrl = E_GicDistCtrl_Enable; + arm_dsb(); + + // Enable timeslice timer interrupt + ArmLocalTimer& T = LOCAL_TIMER; + T.iTimerCtrl = 0; + T.iTimerIntStatus = E_ArmTmrIntStatus_Event; + ArmGic::ClearPending(TIMESLICE_VECTOR); + arm_dsb(); + ArmGic::Enable(TIMESLICE_VECTOR); + arm_dsb(); + T.iTimerLoad = KMaxTUint32; // timer wraps to 0xffffffff after reaching 0 + arm_dsb(); + T.iTimerCount = (TUint32)KMaxTInt32; // timer starts at 0x7fffffff (initial thread doesn't timeslice) + arm_dsb(); + + ArmGic::DumpCpuIfc(); + } +