diff -r 000000000000 -r a41df078684a kernel/eka/nkernsmp/x86/ncirq.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/nkernsmp/x86/ncirq.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,319 @@ +// Copyright (c) 2007-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\x86\ncirq.cpp +// +// + +/** + @file + @internalTechnology +*/ + +#include "nk_priv.h" +#include "nk_plat.h" +#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>24; + } + +TUint32 TIoApic::Control(TInt aIndex) + { + TUint32 reg = 2*aIndex + 0x10; + TInt irq = __SPIN_LOCK_IRQSAVE(iLock); + IO_APIC_SELECT(reg); + TUint32 x = IO_APIC_REG; + __SPIN_UNLOCK_IRQRESTORE(iLock,irq); + return x; + } + +TUint32 TIoApic::ModifyDest(TInt aIndex, TUint32 aNewDest) + { + TUint32 reg = 2*aIndex + 0x11; + TInt irq = __SPIN_LOCK_IRQSAVE(iLock); + IO_APIC_SELECT(reg); + TUint32 x = IO_APIC_REG; + IO_APIC_REG = (x&0x00ffffffu) | (aNewDest<<24); + __SPIN_UNLOCK_IRQRESTORE(iLock,irq); + return x>>24; + } + +TUint32 TIoApic::ModifyControl(TInt aIndex, TUint32 aClear, TUint32 aSet) + { + TUint32 reg = 2*aIndex + 0x10; + TInt irq = __SPIN_LOCK_IRQSAVE(iLock); + IO_APIC_SELECT(reg); + TUint32 x = IO_APIC_REG; + x &= ~aClear; + x |= aSet; + IO_APIC_SELECT(reg); + IO_APIC_REG = x; + __SPIN_UNLOCK_IRQRESTORE(iLock,irq); + return x; + } + +void TIoApic::Dump() + { + TUint32 id = Id(); + TUint32 ver = Ver(); + TUint32 arb = Arb(); + __KTRACE_OPT(KBOOT,DEBUGPRINT("IOAPIC ID=%08x VER=%08x ARB=%08x", id, ver, arb)); + + TInt max = (ver>>16)&0xff; + TInt i; + for (i=0; i<=max; ++i) + { + TUint32 dest = Dest(i); + TUint32 ctrl = Control(i); + __KTRACE_OPT(KBOOT,DEBUGPRINT("IOAPIC[%02x] DEST=%02x CTRL=%08x", i, dest, ctrl)); + } + } + + +void NIrq::HwEoi() + { + if (iX && iX->iEoiFn) + (*iX->iEoiFn)(this); + else + { + volatile TUint32* const apic_eoi = (volatile TUint32*)(X86_LOCAL_APIC_BASE + X86_LOCAL_APIC_OFFSET_EOI); + *apic_eoi = 0; + } + } + +void NIrq::HwEnable() + { + if (iX && iX->iEnableFn) + (*iX->iEnableFn)(this); + else + { +// if ((iStaticFlags & ELevel) || (iIState & ERaw)) + TheIoApic.ModifyControl(iIndex, IO_APIC_CTRL_IMASK, 0); + } + } + +void NIrq::HwDisable() + { + if (iX && iX->iDisableFn) + (*iX->iDisableFn)(this); + else + { + if ((iStaticFlags & ELevel) || (iIState & ERaw)) + TheIoApic.ModifyControl(iIndex, 0, IO_APIC_CTRL_IMASK); + } + } + +void NIrq::HwSetCpu(TInt aCpu) + { + if (iX && iX->iSetCpuFn) + (*iX->iSetCpuFn)(this, 1u<iSetCpuFn) + (*iX->iSetCpuFn)(this, aMask); + else + { + TheIoApic.ModifyDest(iIndex, aMask); + } + } + +void NIrq::HwInit() + { + if (iX && iX->iInitFn) + (*iX->iInitFn)(this); + else + { + __KTRACE_OPT(KBOOT,DEBUGPRINT("NIrq %02x HwInit", iIndex)); + TUint32 clear = IO_APIC_CTRL_INTVEC_MASK; + TUint32 set = iVector & IO_APIC_CTRL_INTVEC_MASK; + set |= IO_APIC_CTRL_IMASK; + if (iStaticFlags & ELevel) + set |= (IO_APIC_CTRL_LEVEL /*| IO_APIC_CTRL_IMASK*/); + else + clear |= (IO_APIC_CTRL_LEVEL /*| IO_APIC_CTRL_IMASK*/); + if (iStaticFlags & EPolarity) + clear |= IO_APIC_CTRL_INTPOL_LOW; + else + set |= IO_APIC_CTRL_INTPOL_LOW; + TheIoApic.ModifyControl(iIndex, clear, set); + TheIoApic.Dump(); + } + } + +TBool NIrq::HwPending() + { + if (iX && iX->iPendingFn) + return (*iX->iPendingFn)(this); + return FALSE; + } + +void NIrq::HwWaitCpus() + { + if (iX && iX->iWaitFn) + (*iX->iWaitFn)(this); + } + +void NIrq::HwInit0() + { + TheIoApic.Dump(); + TInt n = 1 + (TheIoApic.Ver() >> 16); + TInt i; + for (i=0; i15) + { + TheIoApic.ModifyControl(i, 0, IO_APIC_CTRL_LEVEL | IO_APIC_CTRL_INTPOL_LOW); + } + } + TheIoApic.Dump(); + } + +void NIrq::HwInit1() + { + write_apic_reg(SIVR, 0x300 | SPURIOUS_INTERRUPT_VECTOR); + write_apic_reg(DIVCNF, 10); // APIC timer clock divide by 128 (bus clock freq / 128) + write_apic_reg(LVTTMR, 0x10000|TIMESLICE_VECTOR); + write_apic_reg(DFR, 0xf0000000u); // set flat logical destination mode + write_apic_reg(LDR, 0x01000000u); // this CPU will be selected by logical destination with bit 0 set + } + +void NIrq::HwInit2AP() + { + TInt cpu = NKern::CurrentCpu(); + write_apic_reg(SIVR, 0x300 | SPURIOUS_INTERRUPT_VECTOR); + write_apic_reg(DIVCNF, 10); + write_apic_reg(LVTTMR, 0x10000|TIMESLICE_VECTOR); + write_apic_reg(DFR, 0xf0000000u); // set flat logical destination mode + write_apic_reg(LDR, 0x01000000u<