kernel/eka/nkernsmp/x86/nccpu.cpp
changeset 0 a41df078684a
child 90 947f0dc9f7a8
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32\nkernsmp\x86\nccpu.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <x86.h>
       
    19 #include <apic.h>
       
    20 
       
    21 
       
    22 const TLinAddr KWarmResetTrampolineAddr = 0x467;
       
    23 
       
    24 TLinAddr ApTrampolinePage = 0;		// overridden in multiple memory model with linear address
       
    25 
       
    26 extern "C" void nanowait(TUint32 aNanoseconds);
       
    27 void cmos_write(TUint32 val, TUint32 addr);
       
    28 void SetupApInitInfo(volatile SApInitInfo&);
       
    29 void _ApMain();
       
    30 
       
    31 TInt WakeAP(TInt aAPICID)
       
    32 	{
       
    33 	__KTRACE_OPT(KBOOT,DEBUGPRINT("WakeAP %d", aAPICID));
       
    34 	read_apic_reg(SIVR);
       
    35 	write_apic_reg(ESR, 0);
       
    36 	read_apic_reg(ESR);
       
    37 
       
    38 	__KTRACE_OPT(KBOOT,DEBUGPRINT("Asserting INIT"));
       
    39 
       
    40 	//Turn INIT on target chip
       
    41 	write_apic_reg(ICRH, aAPICID<<24);
       
    42 
       
    43 	// Send IPI
       
    44 	write_apic_reg(ICRL, 0xC500);
       
    45 
       
    46 	__KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish..."));
       
    47 	TInt timeout = 0;
       
    48 	TUint32 send_status;
       
    49 	TUint32 accept_status;
       
    50 	do	{
       
    51 		__KTRACE_OPT(KBOOT,DEBUGPRINT("+"));
       
    52 		nanowait(100000);
       
    53 		send_status = read_apic_reg(ICRL) & 0x1000;
       
    54 		} while (send_status && (++timeout < 1000));
       
    55 
       
    56 	nanowait(10000000);
       
    57 
       
    58 	__KTRACE_OPT(KBOOT,DEBUGPRINT("Deasserting INIT"));
       
    59 
       
    60 	//	Target chip
       
    61 	write_apic_reg(ICRH, aAPICID<<24);
       
    62 
       
    63 	//	Send IPI
       
    64 	write_apic_reg(ICRL, 0x8500);
       
    65 
       
    66 	__KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish..."));
       
    67 	timeout = 0;
       
    68 	do	{
       
    69 		__KTRACE_OPT(KBOOT,DEBUGPRINT("+"));
       
    70 		nanowait(100000);
       
    71 		send_status = read_apic_reg(ICRL) & 0x1000;
       
    72 		} while (send_status && (++timeout < 1000));
       
    73 
       
    74 	/*
       
    75 	 * Should we send STARTUP IPIs ?
       
    76 	 *
       
    77 	 * Determine this based on the APIC version.
       
    78 	 * If we don't have an integrated APIC, don't send the STARTUP IPIs.
       
    79 	 */
       
    80 //	if (APIC_INTEGRATED(apic_version[phys_apicid]))
       
    81 	TInt num_starts = 2;
       
    82 //	else
       
    83 //		num_starts = 0;
       
    84 
       
    85 	// Run STARTUP IPI loop.
       
    86 //	maxlvt = get_maxlvt();
       
    87 
       
    88 	TInt j;
       
    89 	for (j = 1; j <= num_starts; j++)
       
    90 		{
       
    91 		__KTRACE_OPT(KBOOT,DEBUGPRINT("Sending STARTUP %d",j));
       
    92 		read_apic_reg(SIVR);
       
    93 		write_apic_reg(ESR, 0);
       
    94 		read_apic_reg(ESR);
       
    95 
       
    96 		// target chip
       
    97 		write_apic_reg(ICRH, aAPICID<<24);
       
    98 
       
    99 		// send startup IPI
       
   100 		write_apic_reg(ICRL, (0x600 | (KApBootPage>>12)));
       
   101 
       
   102 		// give other CPU time to accept it
       
   103 		nanowait(300000);
       
   104 
       
   105 		__KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish..."));
       
   106 		timeout = 0;
       
   107 		do	{
       
   108 			__KTRACE_OPT(KBOOT,DEBUGPRINT("+"));
       
   109 			nanowait(100000);
       
   110 			send_status = read_apic_reg(ICRL) & 0x1000;
       
   111 			} while (send_status && (++timeout < 1000));
       
   112 
       
   113 		// give other CPU time to accept it
       
   114 		nanowait(300000);
       
   115 
       
   116 		/*
       
   117 		 * Due to the Pentium erratum 3AP.
       
   118 		 */
       
   119 //		if (maxlvt > 3) {
       
   120 //			read_apic_reg(APIC_SPIV);
       
   121 //			write_apic_reg(APIC_ESR, 0);
       
   122 //		}
       
   123 		accept_status = (read_apic_reg(ESR) & 0xEF);
       
   124 		if (send_status || accept_status)
       
   125 			break;
       
   126 		}
       
   127 	__KTRACE_OPT(KBOOT,DEBUGPRINT("After startup"));
       
   128 
       
   129 	if (send_status)
       
   130 		__KTRACE_OPT(KBOOT,DEBUGPRINT("APIC never delivered???"));
       
   131 	if (accept_status)
       
   132 		__KTRACE_OPT(KBOOT,DEBUGPRINT("APIC delivery error %x", accept_status));
       
   133 
       
   134 	return (send_status | accept_status);
       
   135 	}
       
   136 
       
   137 
       
   138 
       
   139 TInt NKern::BootAP(volatile SAPBootInfo* aInfo)
       
   140 	{
       
   141 	__KTRACE_OPT(KBOOT,DEBUGPRINT("NKern::BootAP %08x %08x+%x", aInfo->iCpu, aInfo->iInitStackBase, aInfo->iInitStackSize));
       
   142 
       
   143 	cmos_write(0xa, 0xf);
       
   144 
       
   145 	TUint8* t = (TUint8*)(KWarmResetTrampolineAddr + ApTrampolinePage);
       
   146 	TUint cs = KApBootPage>>4;
       
   147 	*t++ = 0;	// IP low
       
   148 	*t++ = 0;	// IP high
       
   149 	*t++ = (TUint8)cs;
       
   150 	*t++ = cs>>8;
       
   151 
       
   152 	volatile SApInitInfo& a = *(volatile SApInitInfo*)KApBootPage;
       
   153 	TCpuPages& cp=X86::CpuPage();
       
   154 	SetupApInitInfo(a);
       
   155 	memcpy((TAny*)a.iTempGdt, cp.iGdt, sizeof(cp.iGdt));
       
   156 	a.iTempGdtr = TUint64(KApBootPage + _FOFF(SApInitInfo,iTempGdt))<<16 | TUint64(KSmpGdtSize*sizeof(SX86Des)-1);
       
   157 	a.iRgs.iCs = RING0_CS;
       
   158 	a.iRgs.iEip = (TLinAddr)&_ApMain;
       
   159 	a.iBootFlag = 0;
       
   160 	a.iBootFlag2 = 0;
       
   161 	a.iLinAddr = (TLinAddr)&a;
       
   162 
       
   163 	a.iStackBase = aInfo->iInitStackBase;
       
   164 	a.iStackSize = aInfo->iInitStackSize;
       
   165 	a.iRgs.iEsp = a.iStackBase + a.iStackSize;
       
   166 	a.iExtra = (TAny*)aInfo;
       
   167 
       
   168 	TInt r = WakeAP(aInfo->iCpu);
       
   169 	if (r!=0)
       
   170 		return KErrGeneral;
       
   171 
       
   172 	TInt timeout = 500;
       
   173 	while (--timeout)
       
   174 		{
       
   175 		nanowait(1000000);
       
   176 		if (a.iBootFlag == KBootFlagMagic-1)
       
   177 			break;
       
   178 		__chill();
       
   179 		}
       
   180 	__KTRACE_OPT(KBOOT, DEBUGPRINT("iBootFlag=%08x",a.iBootFlag));
       
   181 	if (timeout==0)
       
   182 		return KErrTimedOut;
       
   183 
       
   184 	__e32_atomic_add_ord32(&a.iBootFlag, TUint32(-1));
       
   185 
       
   186 	NKern::DisableAllInterrupts();
       
   187 	while (a.iBootFlag2==0)
       
   188 		{}
       
   189 	__e32_io_completion_barrier();
       
   190 	a.iBootFlag2 = 2;
       
   191 	__e32_io_completion_barrier();
       
   192 	a.iBPTimestamp = X86::Timestamp();
       
   193 	__e32_io_completion_barrier();
       
   194 	while (a.iBootFlag2==2)
       
   195 		{}
       
   196 	__e32_io_completion_barrier();
       
   197 	NKern::EnableAllInterrupts();
       
   198 
       
   199 	return KErrNone;
       
   200 	}
       
   201 
       
   202 void InitAPTimestamp(SNThreadCreateInfo&)
       
   203 	{
       
   204 	volatile SApInitInfo& a = *(volatile SApInitInfo*)KApBootPage;
       
   205 	NKern::DisableAllInterrupts();
       
   206 	a.iBootFlag2 = 1;
       
   207 	__e32_io_completion_barrier();
       
   208 	while (a.iBootFlag2==1)
       
   209 		{}
       
   210 	__e32_io_completion_barrier();
       
   211 	a.iAPTimestamp = X86::Timestamp();
       
   212 	__e32_io_completion_barrier();
       
   213 	TUint64 bpt = a.iBPTimestamp;
       
   214 	TUint64 apt = a.iAPTimestamp;
       
   215 	TUint64 delta = bpt - apt;
       
   216 	TSubScheduler& ss = SubScheduler();
       
   217 	ss.iLastTimestamp64 += delta;
       
   218 	*(TUint64*)&ss.i_TimestampOffset = delta;
       
   219 	__KTRACE_OPT(KBOOT,DEBUGPRINT("APT=0x%lx BPT=0x%lx Delta=0x%lx", apt, bpt, delta));
       
   220 	__e32_io_completion_barrier();
       
   221 	a.iBootFlag2 = 3;
       
   222 	NKern::EnableAllInterrupts();
       
   223 	}
       
   224 
       
   225 
       
   226