1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/nkernsmp/x86/nccpu.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,226 @@
1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\nkernsmp\x86\nccpu.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include <x86.h>
1.22 +#include <apic.h>
1.23 +
1.24 +
1.25 +const TLinAddr KWarmResetTrampolineAddr = 0x467;
1.26 +
1.27 +TLinAddr ApTrampolinePage = 0; // overridden in multiple memory model with linear address
1.28 +
1.29 +extern "C" void nanowait(TUint32 aNanoseconds);
1.30 +void cmos_write(TUint32 val, TUint32 addr);
1.31 +void SetupApInitInfo(volatile SApInitInfo&);
1.32 +void _ApMain();
1.33 +
1.34 +TInt WakeAP(TInt aAPICID)
1.35 + {
1.36 + __KTRACE_OPT(KBOOT,DEBUGPRINT("WakeAP %d", aAPICID));
1.37 + read_apic_reg(SIVR);
1.38 + write_apic_reg(ESR, 0);
1.39 + read_apic_reg(ESR);
1.40 +
1.41 + __KTRACE_OPT(KBOOT,DEBUGPRINT("Asserting INIT"));
1.42 +
1.43 + //Turn INIT on target chip
1.44 + write_apic_reg(ICRH, aAPICID<<24);
1.45 +
1.46 + // Send IPI
1.47 + write_apic_reg(ICRL, 0xC500);
1.48 +
1.49 + __KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish..."));
1.50 + TInt timeout = 0;
1.51 + TUint32 send_status;
1.52 + TUint32 accept_status;
1.53 + do {
1.54 + __KTRACE_OPT(KBOOT,DEBUGPRINT("+"));
1.55 + nanowait(100000);
1.56 + send_status = read_apic_reg(ICRL) & 0x1000;
1.57 + } while (send_status && (++timeout < 1000));
1.58 +
1.59 + nanowait(10000000);
1.60 +
1.61 + __KTRACE_OPT(KBOOT,DEBUGPRINT("Deasserting INIT"));
1.62 +
1.63 + // Target chip
1.64 + write_apic_reg(ICRH, aAPICID<<24);
1.65 +
1.66 + // Send IPI
1.67 + write_apic_reg(ICRL, 0x8500);
1.68 +
1.69 + __KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish..."));
1.70 + timeout = 0;
1.71 + do {
1.72 + __KTRACE_OPT(KBOOT,DEBUGPRINT("+"));
1.73 + nanowait(100000);
1.74 + send_status = read_apic_reg(ICRL) & 0x1000;
1.75 + } while (send_status && (++timeout < 1000));
1.76 +
1.77 + /*
1.78 + * Should we send STARTUP IPIs ?
1.79 + *
1.80 + * Determine this based on the APIC version.
1.81 + * If we don't have an integrated APIC, don't send the STARTUP IPIs.
1.82 + */
1.83 +// if (APIC_INTEGRATED(apic_version[phys_apicid]))
1.84 + TInt num_starts = 2;
1.85 +// else
1.86 +// num_starts = 0;
1.87 +
1.88 + // Run STARTUP IPI loop.
1.89 +// maxlvt = get_maxlvt();
1.90 +
1.91 + TInt j;
1.92 + for (j = 1; j <= num_starts; j++)
1.93 + {
1.94 + __KTRACE_OPT(KBOOT,DEBUGPRINT("Sending STARTUP %d",j));
1.95 + read_apic_reg(SIVR);
1.96 + write_apic_reg(ESR, 0);
1.97 + read_apic_reg(ESR);
1.98 +
1.99 + // target chip
1.100 + write_apic_reg(ICRH, aAPICID<<24);
1.101 +
1.102 + // send startup IPI
1.103 + write_apic_reg(ICRL, (0x600 | (KApBootPage>>12)));
1.104 +
1.105 + // give other CPU time to accept it
1.106 + nanowait(300000);
1.107 +
1.108 + __KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish..."));
1.109 + timeout = 0;
1.110 + do {
1.111 + __KTRACE_OPT(KBOOT,DEBUGPRINT("+"));
1.112 + nanowait(100000);
1.113 + send_status = read_apic_reg(ICRL) & 0x1000;
1.114 + } while (send_status && (++timeout < 1000));
1.115 +
1.116 + // give other CPU time to accept it
1.117 + nanowait(300000);
1.118 +
1.119 + /*
1.120 + * Due to the Pentium erratum 3AP.
1.121 + */
1.122 +// if (maxlvt > 3) {
1.123 +// read_apic_reg(APIC_SPIV);
1.124 +// write_apic_reg(APIC_ESR, 0);
1.125 +// }
1.126 + accept_status = (read_apic_reg(ESR) & 0xEF);
1.127 + if (send_status || accept_status)
1.128 + break;
1.129 + }
1.130 + __KTRACE_OPT(KBOOT,DEBUGPRINT("After startup"));
1.131 +
1.132 + if (send_status)
1.133 + __KTRACE_OPT(KBOOT,DEBUGPRINT("APIC never delivered???"));
1.134 + if (accept_status)
1.135 + __KTRACE_OPT(KBOOT,DEBUGPRINT("APIC delivery error %x", accept_status));
1.136 +
1.137 + return (send_status | accept_status);
1.138 + }
1.139 +
1.140 +
1.141 +
1.142 +TInt NKern::BootAP(volatile SAPBootInfo* aInfo)
1.143 + {
1.144 + __KTRACE_OPT(KBOOT,DEBUGPRINT("NKern::BootAP %08x %08x+%x", aInfo->iCpu, aInfo->iInitStackBase, aInfo->iInitStackSize));
1.145 +
1.146 + cmos_write(0xa, 0xf);
1.147 +
1.148 + TUint8* t = (TUint8*)(KWarmResetTrampolineAddr + ApTrampolinePage);
1.149 + TUint cs = KApBootPage>>4;
1.150 + *t++ = 0; // IP low
1.151 + *t++ = 0; // IP high
1.152 + *t++ = (TUint8)cs;
1.153 + *t++ = cs>>8;
1.154 +
1.155 + volatile SApInitInfo& a = *(volatile SApInitInfo*)KApBootPage;
1.156 + TCpuPages& cp=X86::CpuPage();
1.157 + SetupApInitInfo(a);
1.158 + memcpy((TAny*)a.iTempGdt, cp.iGdt, sizeof(cp.iGdt));
1.159 + a.iTempGdtr = TUint64(KApBootPage + _FOFF(SApInitInfo,iTempGdt))<<16 | TUint64(KSmpGdtSize*sizeof(SX86Des)-1);
1.160 + a.iRgs.iCs = RING0_CS;
1.161 + a.iRgs.iEip = (TLinAddr)&_ApMain;
1.162 + a.iBootFlag = 0;
1.163 + a.iBootFlag2 = 0;
1.164 + a.iLinAddr = (TLinAddr)&a;
1.165 +
1.166 + a.iStackBase = aInfo->iInitStackBase;
1.167 + a.iStackSize = aInfo->iInitStackSize;
1.168 + a.iRgs.iEsp = a.iStackBase + a.iStackSize;
1.169 + a.iExtra = (TAny*)aInfo;
1.170 +
1.171 + TInt r = WakeAP(aInfo->iCpu);
1.172 + if (r!=0)
1.173 + return KErrGeneral;
1.174 +
1.175 + TInt timeout = 500;
1.176 + while (--timeout)
1.177 + {
1.178 + nanowait(1000000);
1.179 + if (a.iBootFlag == KBootFlagMagic-1)
1.180 + break;
1.181 + __chill();
1.182 + }
1.183 + __KTRACE_OPT(KBOOT, DEBUGPRINT("iBootFlag=%08x",a.iBootFlag));
1.184 + if (timeout==0)
1.185 + return KErrTimedOut;
1.186 +
1.187 + __e32_atomic_add_ord32(&a.iBootFlag, TUint32(-1));
1.188 +
1.189 + NKern::DisableAllInterrupts();
1.190 + while (a.iBootFlag2==0)
1.191 + {}
1.192 + __e32_io_completion_barrier();
1.193 + a.iBootFlag2 = 2;
1.194 + __e32_io_completion_barrier();
1.195 + a.iBPTimestamp = X86::Timestamp();
1.196 + __e32_io_completion_barrier();
1.197 + while (a.iBootFlag2==2)
1.198 + {}
1.199 + __e32_io_completion_barrier();
1.200 + NKern::EnableAllInterrupts();
1.201 +
1.202 + return KErrNone;
1.203 + }
1.204 +
1.205 +void InitAPTimestamp(SNThreadCreateInfo&)
1.206 + {
1.207 + volatile SApInitInfo& a = *(volatile SApInitInfo*)KApBootPage;
1.208 + NKern::DisableAllInterrupts();
1.209 + a.iBootFlag2 = 1;
1.210 + __e32_io_completion_barrier();
1.211 + while (a.iBootFlag2==1)
1.212 + {}
1.213 + __e32_io_completion_barrier();
1.214 + a.iAPTimestamp = X86::Timestamp();
1.215 + __e32_io_completion_barrier();
1.216 + TUint64 bpt = a.iBPTimestamp;
1.217 + TUint64 apt = a.iAPTimestamp;
1.218 + TUint64 delta = bpt - apt;
1.219 + TSubScheduler& ss = SubScheduler();
1.220 + ss.iLastTimestamp64 += delta;
1.221 + *(TUint64*)&ss.i_TimestampOffset = delta;
1.222 + __KTRACE_OPT(KBOOT,DEBUGPRINT("APT=0x%lx BPT=0x%lx Delta=0x%lx", apt, bpt, delta));
1.223 + __e32_io_completion_barrier();
1.224 + a.iBootFlag2 = 3;
1.225 + NKern::EnableAllInterrupts();
1.226 + }
1.227 +
1.228 +
1.229 +