os/kernelhwsrv/kernel/eka/nkernsmp/x86/nccpu.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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