sl@0: // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32\nkernsmp\x86\ncirq.cpp sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @internalTechnology sl@0: */ sl@0: sl@0: #include "nk_priv.h" sl@0: #include "nk_plat.h" sl@0: #include sl@0: #include sl@0: sl@0: #ifdef _DEBUG sl@0: #define DMEMDUMP(base,size) DbgMemDump((TLinAddr)base,size) sl@0: void DbgMemDump(TLinAddr aBase, TInt aSize) sl@0: { sl@0: TInt off; sl@0: const TUint8* p=(const TUint8*)aBase; sl@0: NKern::Lock(); sl@0: for (off=0; off>24; sl@0: } sl@0: sl@0: TUint32 TIoApic::Control(TInt aIndex) sl@0: { sl@0: TUint32 reg = 2*aIndex + 0x10; sl@0: TInt irq = __SPIN_LOCK_IRQSAVE(iLock); sl@0: IO_APIC_SELECT(reg); sl@0: TUint32 x = IO_APIC_REG; sl@0: __SPIN_UNLOCK_IRQRESTORE(iLock,irq); sl@0: return x; sl@0: } sl@0: sl@0: TUint32 TIoApic::ModifyDest(TInt aIndex, TUint32 aNewDest) sl@0: { sl@0: TUint32 reg = 2*aIndex + 0x11; sl@0: TInt irq = __SPIN_LOCK_IRQSAVE(iLock); sl@0: IO_APIC_SELECT(reg); sl@0: TUint32 x = IO_APIC_REG; sl@0: IO_APIC_REG = (x&0x00ffffffu) | (aNewDest<<24); sl@0: __SPIN_UNLOCK_IRQRESTORE(iLock,irq); sl@0: return x>>24; sl@0: } sl@0: sl@0: TUint32 TIoApic::ModifyControl(TInt aIndex, TUint32 aClear, TUint32 aSet) sl@0: { sl@0: TUint32 reg = 2*aIndex + 0x10; sl@0: TInt irq = __SPIN_LOCK_IRQSAVE(iLock); sl@0: IO_APIC_SELECT(reg); sl@0: TUint32 x = IO_APIC_REG; sl@0: x &= ~aClear; sl@0: x |= aSet; sl@0: IO_APIC_SELECT(reg); sl@0: IO_APIC_REG = x; sl@0: __SPIN_UNLOCK_IRQRESTORE(iLock,irq); sl@0: return x; sl@0: } sl@0: sl@0: void TIoApic::Dump() sl@0: { sl@0: TUint32 id = Id(); sl@0: TUint32 ver = Ver(); sl@0: TUint32 arb = Arb(); sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("IOAPIC ID=%08x VER=%08x ARB=%08x", id, ver, arb)); sl@0: sl@0: TInt max = (ver>>16)&0xff; sl@0: TInt i; sl@0: for (i=0; i<=max; ++i) sl@0: { sl@0: TUint32 dest = Dest(i); sl@0: TUint32 ctrl = Control(i); sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("IOAPIC[%02x] DEST=%02x CTRL=%08x", i, dest, ctrl)); sl@0: } sl@0: } sl@0: sl@0: sl@0: void NIrq::HwEoi() sl@0: { sl@0: if (iX && iX->iEoiFn) sl@0: (*iX->iEoiFn)(this); sl@0: else sl@0: { sl@0: volatile TUint32* const apic_eoi = (volatile TUint32*)(X86_LOCAL_APIC_BASE + X86_LOCAL_APIC_OFFSET_EOI); sl@0: *apic_eoi = 0; sl@0: } sl@0: } sl@0: sl@0: void NIrq::HwEnable() sl@0: { sl@0: if (iX && iX->iEnableFn) sl@0: (*iX->iEnableFn)(this); sl@0: else sl@0: { sl@0: // if ((iStaticFlags & ELevel) || (iIState & ERaw)) sl@0: TheIoApic.ModifyControl(iIndex, IO_APIC_CTRL_IMASK, 0); sl@0: } sl@0: } sl@0: sl@0: void NIrq::HwDisable() sl@0: { sl@0: if (iX && iX->iDisableFn) sl@0: (*iX->iDisableFn)(this); sl@0: else sl@0: { sl@0: if ((iStaticFlags & ELevel) || (iIState & ERaw)) sl@0: TheIoApic.ModifyControl(iIndex, 0, IO_APIC_CTRL_IMASK); sl@0: } sl@0: } sl@0: sl@0: void NIrq::HwSetCpu(TInt aCpu) sl@0: { sl@0: if (iX && iX->iSetCpuFn) sl@0: (*iX->iSetCpuFn)(this, 1u<iSetCpuFn) sl@0: (*iX->iSetCpuFn)(this, aMask); sl@0: else sl@0: { sl@0: TheIoApic.ModifyDest(iIndex, aMask); sl@0: } sl@0: } sl@0: sl@0: void NIrq::HwInit() sl@0: { sl@0: if (iX && iX->iInitFn) sl@0: (*iX->iInitFn)(this); sl@0: else sl@0: { sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("NIrq %02x HwInit", iIndex)); sl@0: TUint32 clear = IO_APIC_CTRL_INTVEC_MASK; sl@0: TUint32 set = iVector & IO_APIC_CTRL_INTVEC_MASK; sl@0: set |= IO_APIC_CTRL_IMASK; sl@0: if (iStaticFlags & ELevel) sl@0: set |= (IO_APIC_CTRL_LEVEL /*| IO_APIC_CTRL_IMASK*/); sl@0: else sl@0: clear |= (IO_APIC_CTRL_LEVEL /*| IO_APIC_CTRL_IMASK*/); sl@0: if (iStaticFlags & EPolarity) sl@0: clear |= IO_APIC_CTRL_INTPOL_LOW; sl@0: else sl@0: set |= IO_APIC_CTRL_INTPOL_LOW; sl@0: TheIoApic.ModifyControl(iIndex, clear, set); sl@0: TheIoApic.Dump(); sl@0: } sl@0: } sl@0: sl@0: TBool NIrq::HwPending() sl@0: { sl@0: if (iX && iX->iPendingFn) sl@0: return (*iX->iPendingFn)(this); sl@0: return FALSE; sl@0: } sl@0: sl@0: void NIrq::HwWaitCpus() sl@0: { sl@0: if (iX && iX->iWaitFn) sl@0: (*iX->iWaitFn)(this); sl@0: } sl@0: sl@0: void NIrq::HwInit0() sl@0: { sl@0: TheIoApic.Dump(); sl@0: TInt n = 1 + (TheIoApic.Ver() >> 16); sl@0: TInt i; sl@0: for (i=0; i15) sl@0: { sl@0: TheIoApic.ModifyControl(i, 0, IO_APIC_CTRL_LEVEL | IO_APIC_CTRL_INTPOL_LOW); sl@0: } sl@0: } sl@0: TheIoApic.Dump(); sl@0: } sl@0: sl@0: void NIrq::HwInit1() sl@0: { sl@0: write_apic_reg(SIVR, 0x300 | SPURIOUS_INTERRUPT_VECTOR); sl@0: write_apic_reg(DIVCNF, 10); // APIC timer clock divide by 128 (bus clock freq / 128) sl@0: write_apic_reg(LVTTMR, 0x10000|TIMESLICE_VECTOR); sl@0: write_apic_reg(DFR, 0xf0000000u); // set flat logical destination mode sl@0: write_apic_reg(LDR, 0x01000000u); // this CPU will be selected by logical destination with bit 0 set sl@0: } sl@0: sl@0: void NIrq::HwInit2AP() sl@0: { sl@0: TInt cpu = NKern::CurrentCpu(); sl@0: write_apic_reg(SIVR, 0x300 | SPURIOUS_INTERRUPT_VECTOR); sl@0: write_apic_reg(DIVCNF, 10); sl@0: write_apic_reg(LVTTMR, 0x10000|TIMESLICE_VECTOR); sl@0: write_apic_reg(DFR, 0xf0000000u); // set flat logical destination mode sl@0: write_apic_reg(LDR, 0x01000000u<