sl@0: // Copyright (c) 2006-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\nccpu.cpp sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: sl@0: sl@0: const TLinAddr KWarmResetTrampolineAddr = 0x467; sl@0: sl@0: TLinAddr ApTrampolinePage = 0; // overridden in multiple memory model with linear address sl@0: sl@0: extern "C" void nanowait(TUint32 aNanoseconds); sl@0: void cmos_write(TUint32 val, TUint32 addr); sl@0: void SetupApInitInfo(volatile SApInitInfo&); sl@0: void _ApMain(); sl@0: sl@0: TInt WakeAP(TInt aAPICID) sl@0: { sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("WakeAP %d", aAPICID)); sl@0: read_apic_reg(SIVR); sl@0: write_apic_reg(ESR, 0); sl@0: read_apic_reg(ESR); sl@0: sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("Asserting INIT")); sl@0: sl@0: //Turn INIT on target chip sl@0: write_apic_reg(ICRH, aAPICID<<24); sl@0: sl@0: // Send IPI sl@0: write_apic_reg(ICRL, 0xC500); sl@0: sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish...")); sl@0: TInt timeout = 0; sl@0: TUint32 send_status; sl@0: TUint32 accept_status; sl@0: do { sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("+")); sl@0: nanowait(100000); sl@0: send_status = read_apic_reg(ICRL) & 0x1000; sl@0: } while (send_status && (++timeout < 1000)); sl@0: sl@0: nanowait(10000000); sl@0: sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("Deasserting INIT")); sl@0: sl@0: // Target chip sl@0: write_apic_reg(ICRH, aAPICID<<24); sl@0: sl@0: // Send IPI sl@0: write_apic_reg(ICRL, 0x8500); sl@0: sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish...")); sl@0: timeout = 0; sl@0: do { sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("+")); sl@0: nanowait(100000); sl@0: send_status = read_apic_reg(ICRL) & 0x1000; sl@0: } while (send_status && (++timeout < 1000)); sl@0: sl@0: /* sl@0: * Should we send STARTUP IPIs ? sl@0: * sl@0: * Determine this based on the APIC version. sl@0: * If we don't have an integrated APIC, don't send the STARTUP IPIs. sl@0: */ sl@0: // if (APIC_INTEGRATED(apic_version[phys_apicid])) sl@0: TInt num_starts = 2; sl@0: // else sl@0: // num_starts = 0; sl@0: sl@0: // Run STARTUP IPI loop. sl@0: // maxlvt = get_maxlvt(); sl@0: sl@0: TInt j; sl@0: for (j = 1; j <= num_starts; j++) sl@0: { sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("Sending STARTUP %d",j)); sl@0: read_apic_reg(SIVR); sl@0: write_apic_reg(ESR, 0); sl@0: read_apic_reg(ESR); sl@0: sl@0: // target chip sl@0: write_apic_reg(ICRH, aAPICID<<24); sl@0: sl@0: // send startup IPI sl@0: write_apic_reg(ICRL, (0x600 | (KApBootPage>>12))); sl@0: sl@0: // give other CPU time to accept it sl@0: nanowait(300000); sl@0: sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish...")); sl@0: timeout = 0; sl@0: do { sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("+")); sl@0: nanowait(100000); sl@0: send_status = read_apic_reg(ICRL) & 0x1000; sl@0: } while (send_status && (++timeout < 1000)); sl@0: sl@0: // give other CPU time to accept it sl@0: nanowait(300000); sl@0: sl@0: /* sl@0: * Due to the Pentium erratum 3AP. sl@0: */ sl@0: // if (maxlvt > 3) { sl@0: // read_apic_reg(APIC_SPIV); sl@0: // write_apic_reg(APIC_ESR, 0); sl@0: // } sl@0: accept_status = (read_apic_reg(ESR) & 0xEF); sl@0: if (send_status || accept_status) sl@0: break; sl@0: } sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("After startup")); sl@0: sl@0: if (send_status) sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("APIC never delivered???")); sl@0: if (accept_status) sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("APIC delivery error %x", accept_status)); sl@0: sl@0: return (send_status | accept_status); sl@0: } sl@0: sl@0: sl@0: sl@0: TInt NKern::BootAP(volatile SAPBootInfo* aInfo) sl@0: { sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("NKern::BootAP %08x %08x+%x", aInfo->iCpu, aInfo->iInitStackBase, aInfo->iInitStackSize)); sl@0: sl@0: cmos_write(0xa, 0xf); sl@0: sl@0: TUint8* t = (TUint8*)(KWarmResetTrampolineAddr + ApTrampolinePage); sl@0: TUint cs = KApBootPage>>4; sl@0: *t++ = 0; // IP low sl@0: *t++ = 0; // IP high sl@0: *t++ = (TUint8)cs; sl@0: *t++ = cs>>8; sl@0: sl@0: volatile SApInitInfo& a = *(volatile SApInitInfo*)KApBootPage; sl@0: TCpuPages& cp=X86::CpuPage(); sl@0: SetupApInitInfo(a); sl@0: memcpy((TAny*)a.iTempGdt, cp.iGdt, sizeof(cp.iGdt)); sl@0: a.iTempGdtr = TUint64(KApBootPage + _FOFF(SApInitInfo,iTempGdt))<<16 | TUint64(KSmpGdtSize*sizeof(SX86Des)-1); sl@0: a.iRgs.iCs = RING0_CS; sl@0: a.iRgs.iEip = (TLinAddr)&_ApMain; sl@0: a.iBootFlag = 0; sl@0: a.iBootFlag2 = 0; sl@0: a.iLinAddr = (TLinAddr)&a; sl@0: sl@0: a.iStackBase = aInfo->iInitStackBase; sl@0: a.iStackSize = aInfo->iInitStackSize; sl@0: a.iRgs.iEsp = a.iStackBase + a.iStackSize; sl@0: a.iExtra = (TAny*)aInfo; sl@0: sl@0: TInt r = WakeAP(aInfo->iCpu); sl@0: if (r!=0) sl@0: return KErrGeneral; sl@0: sl@0: TInt timeout = 500; sl@0: while (--timeout) sl@0: { sl@0: nanowait(1000000); sl@0: if (a.iBootFlag == KBootFlagMagic-1) sl@0: break; sl@0: __chill(); sl@0: } sl@0: __KTRACE_OPT(KBOOT, DEBUGPRINT("iBootFlag=%08x",a.iBootFlag)); sl@0: if (timeout==0) sl@0: return KErrTimedOut; sl@0: sl@0: __e32_atomic_add_ord32(&a.iBootFlag, TUint32(-1)); sl@0: sl@0: NKern::DisableAllInterrupts(); sl@0: while (a.iBootFlag2==0) sl@0: {} sl@0: __e32_io_completion_barrier(); sl@0: a.iBootFlag2 = 2; sl@0: __e32_io_completion_barrier(); sl@0: a.iBPTimestamp = X86::Timestamp(); sl@0: __e32_io_completion_barrier(); sl@0: while (a.iBootFlag2==2) sl@0: {} sl@0: __e32_io_completion_barrier(); sl@0: NKern::EnableAllInterrupts(); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: void InitAPTimestamp(SNThreadCreateInfo&) sl@0: { sl@0: volatile SApInitInfo& a = *(volatile SApInitInfo*)KApBootPage; sl@0: NKern::DisableAllInterrupts(); sl@0: a.iBootFlag2 = 1; sl@0: __e32_io_completion_barrier(); sl@0: while (a.iBootFlag2==1) sl@0: {} sl@0: __e32_io_completion_barrier(); sl@0: a.iAPTimestamp = X86::Timestamp(); sl@0: __e32_io_completion_barrier(); sl@0: TUint64 bpt = a.iBPTimestamp; sl@0: TUint64 apt = a.iAPTimestamp; sl@0: TUint64 delta = bpt - apt; sl@0: TSubScheduler& ss = SubScheduler(); sl@0: ss.iLastTimestamp64 += delta; sl@0: *(TUint64*)&ss.i_TimestampOffset = delta; sl@0: __KTRACE_OPT(KBOOT,DEBUGPRINT("APT=0x%lx BPT=0x%lx Delta=0x%lx", apt, bpt, delta)); sl@0: __e32_io_completion_barrier(); sl@0: a.iBootFlag2 = 3; sl@0: NKern::EnableAllInterrupts(); sl@0: } sl@0: sl@0: sl@0: