os/kernelhwsrv/kernel/eka/nkernsmp/x86/nccpu.cpp
changeset 0 bde4ae8d615e
     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 +