\r
#include "RegisterCpuFeatures.h"\r
\r
+CHAR16 *mDependTypeStr[] = {L"None", L"Thread", L"Core", L"Package", L"Invalid" };\r
+CHAR16 *mRegisterTypeStr[] = {L"MSR", L"CR", L"MMIO", L"CACHE", L"SEMAP", L"INVALID" };\r
+\r
/**\r
Worker function to save PcdCpuFeaturesCapability.\r
\r
CPU_FEATURES_INIT_ORDER *InitOrder;\r
CPU_FEATURES_DATA *CpuFeaturesData;\r
LIST_ENTRY *Entry;\r
+ UINT32 Core;\r
+ UINT32 Package;\r
+ UINT32 Thread;\r
+ EFI_CPU_PHYSICAL_LOCATION *Location;\r
+ BOOLEAN *CoresVisited;\r
+ UINTN Index;\r
+ ACPI_CPU_DATA *AcpiCpuData;\r
+ CPU_STATUS_INFORMATION *CpuStatus;\r
+ UINT32 *ValidCoreCountPerPackage;\r
+\r
+ Core = 0;\r
+ Package = 0;\r
+ Thread = 0;\r
\r
CpuFeaturesData = GetCpuFeaturesData ();\r
CpuFeaturesData->InitOrder = AllocateZeroPool (sizeof (CPU_FEATURES_INIT_ORDER) * NumberOfCpus);\r
Entry = Entry->ForwardLink;\r
}\r
\r
+ CpuFeaturesData->NumberOfCpus = (UINT32) NumberOfCpus;\r
+\r
+ AcpiCpuData = GetAcpiCpuData ();\r
+ ASSERT (AcpiCpuData != NULL);\r
+ CpuFeaturesData->AcpiCpuData= AcpiCpuData;\r
+\r
+ CpuStatus = &AcpiCpuData->CpuStatus;\r
+ Location = AllocateZeroPool (sizeof (EFI_CPU_PHYSICAL_LOCATION) * NumberOfCpus);\r
+ ASSERT (Location != NULL);\r
+ AcpiCpuData->ApLocation = (EFI_PHYSICAL_ADDRESS)(UINTN)Location;\r
+\r
for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {\r
InitOrder = &CpuFeaturesData->InitOrder[ProcessorNumber];\r
InitOrder->FeaturesSupportedMask = AllocateZeroPool (CpuFeaturesData->BitMaskSize);\r
&ProcessorInfoBuffer,\r
sizeof (EFI_PROCESSOR_INFORMATION)\r
);\r
+ CopyMem (\r
+ &Location[ProcessorNumber],\r
+ &ProcessorInfoBuffer.Location,\r
+ sizeof (EFI_CPU_PHYSICAL_LOCATION)\r
+ );\r
+\r
+ //\r
+ // Collect CPU package count info.\r
+ //\r
+ if (Package < ProcessorInfoBuffer.Location.Package) {\r
+ Package = ProcessorInfoBuffer.Location.Package;\r
+ }\r
+ //\r
+ // Collect CPU max core count info.\r
+ //\r
+ if (Core < ProcessorInfoBuffer.Location.Core) {\r
+ Core = ProcessorInfoBuffer.Location.Core;\r
+ }\r
+ //\r
+ // Collect CPU max thread count info.\r
+ //\r
+ if (Thread < ProcessorInfoBuffer.Location.Thread) {\r
+ Thread = ProcessorInfoBuffer.Location.Thread;\r
+ }\r
}\r
+ CpuStatus->PackageCount = Package + 1;\r
+ CpuStatus->MaxCoreCount = Core + 1;\r
+ CpuStatus->MaxThreadCount = Thread + 1;\r
+ DEBUG ((DEBUG_INFO, "Processor Info: Package: %d, MaxCore : %d, MaxThread: %d\n",\r
+ CpuStatus->PackageCount,\r
+ CpuStatus->MaxCoreCount,\r
+ CpuStatus->MaxThreadCount));\r
+\r
+ //\r
+ // Collect valid core count in each package because not all cores are valid.\r
+ //\r
+ ValidCoreCountPerPackage= AllocateZeroPool (sizeof (UINT32) * CpuStatus->PackageCount);\r
+ ASSERT (ValidCoreCountPerPackage != 0);\r
+ CpuStatus->ValidCoreCountPerPackage = (EFI_PHYSICAL_ADDRESS)(UINTN)ValidCoreCountPerPackage;\r
+ CoresVisited = AllocatePool (sizeof (BOOLEAN) * CpuStatus->MaxCoreCount);\r
+ ASSERT (CoresVisited != NULL);\r
+\r
+ for (Index = 0; Index < CpuStatus->PackageCount; Index ++ ) {\r
+ ZeroMem (CoresVisited, sizeof (BOOLEAN) * CpuStatus->MaxCoreCount);\r
+ //\r
+ // Collect valid cores in Current package.\r
+ //\r
+ for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {\r
+ Location = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.ProcessorInfo.Location;\r
+ if (Location->Package == Index && !CoresVisited[Location->Core] ) {\r
+ //\r
+ // The ValidCores position for Location->Core is valid.\r
+ // The possible values in ValidCores[Index] are 0 or 1.\r
+ // FALSE means no valid threads in this Core.\r
+ // TRUE means have valid threads in this core, no matter the thead count is 1 or more.\r
+ //\r
+ CoresVisited[Location->Core] = TRUE;\r
+ ValidCoreCountPerPackage[Index]++;\r
+ }\r
+ }\r
+ }\r
+ FreePool (CoresVisited);\r
+\r
+ for (Index = 0; Index <= Package; Index++) {\r
+ DEBUG ((DEBUG_INFO, "Package: %d, Valid Core : %d\n", Index, ValidCoreCountPerPackage[Index]));\r
+ }\r
+\r
+ CpuFeaturesData->CpuFlags.SemaphoreCount = AllocateZeroPool (sizeof (UINT32) * CpuStatus->PackageCount * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount);\r
+ ASSERT (CpuFeaturesData->CpuFlags.SemaphoreCount != NULL);\r
+\r
//\r
// Get support and configuration PCDs\r
//\r
LIST_ENTRY *Entry;\r
CPU_FEATURES_DATA *CpuFeaturesData;\r
\r
- CpuFeaturesData = GetCpuFeaturesData ();\r
+ CpuFeaturesData = (CPU_FEATURES_DATA *)Buffer;\r
ProcessorNumber = GetProcessorIndex ();\r
CpuInfo = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo;\r
//\r
RegisterTableEntry->Value\r
));\r
break;\r
+ case Semaphore:\r
+ DEBUG ((\r
+ DebugPrintErrorLevel,\r
+ "Processor: %d: Semaphore: Scope Value: %s\r\n",\r
+ ProcessorNumber,\r
+ mDependTypeStr[MIN (RegisterTableEntry->Value, InvalidDepType)]\r
+ ));\r
+ break;\r
+\r
default:\r
break;\r
}\r
REGISTER_CPU_FEATURE_INFORMATION *CpuInfo;\r
LIST_ENTRY *Entry;\r
CPU_FEATURES_DATA *CpuFeaturesData;\r
+ LIST_ENTRY *NextEntry;\r
+ CPU_FEATURES_ENTRY *NextCpuFeatureInOrder;\r
+ BOOLEAN Success;\r
+ CPU_FEATURE_DEPENDENCE_TYPE BeforeDep;\r
+ CPU_FEATURE_DEPENDENCE_TYPE AfterDep;\r
\r
CpuFeaturesData = GetCpuFeaturesData ();\r
CpuFeaturesData->CapabilityPcd = AllocatePool (CpuFeaturesData->BitMaskSize);\r
//\r
CpuInfo = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo;\r
Entry = GetFirstNode (&CpuInitOrder->OrderList);\r
+ NextEntry = Entry->ForwardLink;\r
while (!IsNull (&CpuInitOrder->OrderList, Entry)) {\r
CpuFeatureInOrder = CPU_FEATURE_ENTRY_FROM_LINK (Entry);\r
+ if (!IsNull (&CpuInitOrder->OrderList, NextEntry)) {\r
+ NextCpuFeatureInOrder = CPU_FEATURE_ENTRY_FROM_LINK (NextEntry);\r
+ } else {\r
+ NextCpuFeatureInOrder = NULL;\r
+ }\r
+ Success = FALSE;\r
if (IsBitMaskMatch (CpuFeatureInOrder->FeatureMask, CpuFeaturesData->SettingPcd)) {\r
Status = CpuFeatureInOrder->InitializeFunc (ProcessorNumber, CpuInfo, CpuFeatureInOrder->ConfigData, TRUE);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((DEBUG_WARN, "Warning :: Failed to enable Feature: Mask = "));\r
DumpCpuFeatureMask (CpuFeatureInOrder->FeatureMask);\r
}\r
+ } else {\r
+ Success = TRUE;\r
}\r
} else {\r
Status = CpuFeatureInOrder->InitializeFunc (ProcessorNumber, CpuInfo, CpuFeatureInOrder->ConfigData, FALSE);\r
DEBUG ((DEBUG_WARN, "Warning :: Failed to disable Feature: Mask = "));\r
DumpCpuFeatureMask (CpuFeatureInOrder->FeatureMask);\r
}\r
+ } else {\r
+ Success = TRUE;\r
}\r
}\r
- Entry = Entry->ForwardLink;\r
+\r
+ if (Success) {\r
+ //\r
+ // If feature has dependence with the next feature (ONLY care core/package dependency).\r
+ // and feature initialize succeed, add sync semaphere here.\r
+ //\r
+ BeforeDep = DetectFeatureScope (CpuFeatureInOrder, TRUE);\r
+ if (NextCpuFeatureInOrder != NULL) {\r
+ AfterDep = DetectFeatureScope (NextCpuFeatureInOrder, FALSE);\r
+ } else {\r
+ AfterDep = NoneDepType;\r
+ }\r
+ //\r
+ // Assume only one of the depend is valid.\r
+ //\r
+ ASSERT (!(BeforeDep > ThreadDepType && AfterDep > ThreadDepType));\r
+ if (BeforeDep > ThreadDepType) {\r
+ CPU_REGISTER_TABLE_WRITE32 (ProcessorNumber, Semaphore, 0, BeforeDep);\r
+ }\r
+ if (AfterDep > ThreadDepType) {\r
+ CPU_REGISTER_TABLE_WRITE32 (ProcessorNumber, Semaphore, 0, AfterDep);\r
+ }\r
+ }\r
+\r
+ Entry = Entry->ForwardLink;\r
+ NextEntry = Entry->ForwardLink;\r
}\r
\r
//\r
}\r
}\r
\r
+/**\r
+ Increment semaphore by 1.\r
+\r
+ @param Sem IN: 32-bit unsigned integer\r
+\r
+**/\r
+VOID\r
+LibReleaseSemaphore (\r
+ IN OUT volatile UINT32 *Sem\r
+ )\r
+{\r
+ InterlockedIncrement (Sem);\r
+}\r
+\r
+/**\r
+ Decrement the semaphore by 1 if it is not zero.\r
+\r
+ Performs an atomic decrement operation for semaphore.\r
+ The compare exchange operation must be performed using\r
+ MP safe mechanisms.\r
+\r
+ @param Sem IN: 32-bit unsigned integer\r
+\r
+**/\r
+VOID\r
+LibWaitForSemaphore (\r
+ IN OUT volatile UINT32 *Sem\r
+ )\r
+{\r
+ UINT32 Value;\r
+\r
+ do {\r
+ Value = *Sem;\r
+ } while (Value == 0 ||\r
+ InterlockedCompareExchange32 (\r
+ Sem,\r
+ Value,\r
+ Value - 1\r
+ ) != Value);\r
+}\r
+\r
/**\r
Initialize the CPU registers from a register table.\r
\r
- @param[in] ProcessorNumber The index of the CPU executing this function.\r
+ @param[in] RegisterTable The register table for this AP.\r
+ @param[in] ApLocation AP location info for this ap.\r
+ @param[in] CpuStatus CPU status info for this CPU.\r
+ @param[in] CpuFlags Flags data structure used when program the register.\r
\r
@note This service could be called by BSP/APs.\r
**/\r
VOID\r
ProgramProcessorRegister (\r
- IN UINTN ProcessorNumber\r
+ IN CPU_REGISTER_TABLE *RegisterTable,\r
+ IN EFI_CPU_PHYSICAL_LOCATION *ApLocation,\r
+ IN CPU_STATUS_INFORMATION *CpuStatus,\r
+ IN PROGRAM_CPU_REGISTER_FLAGS *CpuFlags\r
)\r
{\r
- CPU_FEATURES_DATA *CpuFeaturesData;\r
- CPU_REGISTER_TABLE *RegisterTable;\r
CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;\r
UINTN Index;\r
UINTN Value;\r
CPU_REGISTER_TABLE_ENTRY *RegisterTableEntryHead;\r
-\r
- CpuFeaturesData = GetCpuFeaturesData ();\r
- RegisterTable = &CpuFeaturesData->RegisterTable[ProcessorNumber];\r
+ volatile UINT32 *SemaphorePtr;\r
+ UINT32 FirstThread;\r
+ UINT32 PackageThreadsCount;\r
+ UINT32 CurrentThread;\r
+ UINTN ProcessorIndex;\r
+ UINTN ThreadIndex;\r
+ UINTN ValidThreadCount;\r
+ UINT32 *ValidCoreCountPerPackage;\r
\r
//\r
// Traverse Register Table of this logical processor\r
\r
RegisterTableEntry = &RegisterTableEntryHead[Index];\r
\r
+ DEBUG_CODE_BEGIN ();\r
+ AcquireSpinLock (&CpuFlags->ConsoleLogLock);\r
+ ThreadIndex = ApLocation->Package * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount +\r
+ ApLocation->Core * CpuStatus->MaxThreadCount +\r
+ ApLocation->Thread;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "Processor = %lu, Entry Index %lu, Type = %s!\n",\r
+ (UINT64)ThreadIndex,\r
+ (UINT64)Index,\r
+ mRegisterTypeStr[MIN ((REGISTER_TYPE)RegisterTableEntry->RegisterType, InvalidReg)]\r
+ ));\r
+ ReleaseSpinLock (&CpuFlags->ConsoleLogLock);\r
+ DEBUG_CODE_END ();\r
+\r
//\r
// Check the type of specified register\r
//\r
// The specified register is Model Specific Register\r
//\r
case Msr:\r
- //\r
- // Get lock to avoid Package/Core scope MSRs programming issue in parallel execution mode\r
- //\r
- AcquireSpinLock (&CpuFeaturesData->MsrLock);\r
if (RegisterTableEntry->ValidBitLength >= 64) {\r
//\r
// If length is not less than 64 bits, then directly write without reading\r
RegisterTableEntry->Value\r
);\r
}\r
- ReleaseSpinLock (&CpuFeaturesData->MsrLock);\r
break;\r
//\r
// MemoryMapped operations\r
//\r
case MemoryMapped:\r
- AcquireSpinLock (&CpuFeaturesData->MemoryMappedLock);\r
+ AcquireSpinLock (&CpuFlags->MemoryMappedLock);\r
MmioBitFieldWrite32 (\r
(UINTN)(RegisterTableEntry->Index | LShiftU64 (RegisterTableEntry->HighIndex, 32)),\r
RegisterTableEntry->ValidBitStart,\r
RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,\r
(UINT32)RegisterTableEntry->Value\r
);\r
- ReleaseSpinLock (&CpuFeaturesData->MemoryMappedLock);\r
+ ReleaseSpinLock (&CpuFlags->MemoryMappedLock);\r
break;\r
//\r
// Enable or disable cache\r
}\r
break;\r
\r
+ case Semaphore:\r
+ // Semaphore works logic like below:\r
+ //\r
+ // V(x) = LibReleaseSemaphore (Semaphore[FirstThread + x]);\r
+ // P(x) = LibWaitForSemaphore (Semaphore[FirstThread + x]);\r
+ //\r
+ // All threads (T0...Tn) waits in P() line and continues running\r
+ // together.\r
+ //\r
+ //\r
+ // T0 T1 ... Tn\r
+ //\r
+ // V(0...n) V(0...n) ... V(0...n)\r
+ // n * P(0) n * P(1) ... n * P(n)\r
+ //\r
+ SemaphorePtr = CpuFlags->SemaphoreCount;\r
+ switch (RegisterTableEntry->Value) {\r
+ case CoreDepType:\r
+ //\r
+ // Get Offset info for the first thread in the core which current thread belongs to.\r
+ //\r
+ FirstThread = (ApLocation->Package * CpuStatus->MaxCoreCount + ApLocation->Core) * CpuStatus->MaxThreadCount;\r
+ CurrentThread = FirstThread + ApLocation->Thread;\r
+ //\r
+ // First Notify all threads in current Core that this thread has ready.\r
+ //\r
+ for (ProcessorIndex = 0; ProcessorIndex < CpuStatus->MaxThreadCount; ProcessorIndex ++) {\r
+ LibReleaseSemaphore ((UINT32 *) &SemaphorePtr[FirstThread + ProcessorIndex]);\r
+ }\r
+ //\r
+ // Second, check whether all valid threads in current core have ready.\r
+ //\r
+ for (ProcessorIndex = 0; ProcessorIndex < CpuStatus->MaxThreadCount; ProcessorIndex ++) {\r
+ LibWaitForSemaphore (&SemaphorePtr[CurrentThread]);\r
+ }\r
+ break;\r
+\r
+ case PackageDepType:\r
+ ValidCoreCountPerPackage = (UINT32 *)(UINTN)CpuStatus->ValidCoreCountPerPackage;\r
+ //\r
+ // Get Offset info for the first thread in the package which current thread belongs to.\r
+ //\r
+ FirstThread = ApLocation->Package * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount;\r
+ //\r
+ // Get the possible threads count for current package.\r
+ //\r
+ PackageThreadsCount = CpuStatus->MaxThreadCount * CpuStatus->MaxCoreCount;\r
+ CurrentThread = FirstThread + CpuStatus->MaxThreadCount * ApLocation->Core + ApLocation->Thread;\r
+ //\r
+ // Get the valid thread count for current package.\r
+ //\r
+ ValidThreadCount = CpuStatus->MaxThreadCount * ValidCoreCountPerPackage[ApLocation->Package];\r
+\r
+ //\r
+ // Different packages may have different valid cores in them. If driver maintail clearly\r
+ // cores number in different packages, the logic will be much complicated.\r
+ // Here driver just simply records the max core number in all packages and use it as expect\r
+ // core number for all packages.\r
+ // In below two steps logic, first current thread will Release semaphore for each thread\r
+ // in current package. Maybe some threads are not valid in this package, but driver don't\r
+ // care. Second, driver will let current thread wait semaphore for all valid threads in\r
+ // current package. Because only the valid threads will do release semaphore for this\r
+ // thread, driver here only need to wait the valid thread count.\r
+ //\r
+\r
+ //\r
+ // First Notify ALL THREADS in current package that this thread has ready.\r
+ //\r
+ for (ProcessorIndex = 0; ProcessorIndex < PackageThreadsCount ; ProcessorIndex ++) {\r
+ LibReleaseSemaphore ((UINT32 *) &SemaphorePtr[FirstThread + ProcessorIndex]);\r
+ }\r
+ //\r
+ // Second, check whether VALID THREADS (not all threads) in current package have ready.\r
+ //\r
+ for (ProcessorIndex = 0; ProcessorIndex < ValidThreadCount; ProcessorIndex ++) {\r
+ LibWaitForSemaphore (&SemaphorePtr[CurrentThread]);\r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+\r
default:\r
break;\r
}\r
IN OUT VOID *Buffer\r
)\r
{\r
- UINTN ProcessorNumber;\r
+ CPU_FEATURES_DATA *CpuFeaturesData;\r
+ CPU_REGISTER_TABLE *RegisterTable;\r
+ CPU_REGISTER_TABLE *RegisterTables;\r
+ UINT32 InitApicId;\r
+ UINTN ProcIndex;\r
+ UINTN Index;\r
+ ACPI_CPU_DATA *AcpiCpuData;\r
\r
- ProcessorNumber = GetProcessorIndex ();\r
- ProgramProcessorRegister (ProcessorNumber);\r
+ CpuFeaturesData = (CPU_FEATURES_DATA *) Buffer;\r
+ AcpiCpuData = CpuFeaturesData->AcpiCpuData;\r
+\r
+ RegisterTables = (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->RegisterTable;\r
+\r
+ InitApicId = GetInitialApicId ();\r
+ RegisterTable = NULL;\r
+ for (Index = 0; Index < AcpiCpuData->NumberOfCpus; Index++) {\r
+ if (RegisterTables[Index].InitialApicId == InitApicId) {\r
+ RegisterTable = &RegisterTables[Index];\r
+ ProcIndex = Index;\r
+ break;\r
+ }\r
+ }\r
+ ASSERT (RegisterTable != NULL);\r
+\r
+ ProgramProcessorRegister (\r
+ RegisterTable,\r
+ (EFI_CPU_PHYSICAL_LOCATION *)(UINTN)AcpiCpuData->ApLocation + ProcIndex,\r
+ &AcpiCpuData->CpuStatus,\r
+ &CpuFeaturesData->CpuFlags\r
+ );\r
}\r
\r
/**\r
{\r
UINTN NumberOfCpus;\r
UINTN NumberOfEnabledProcessors;\r
+ CPU_FEATURES_DATA *CpuFeaturesData;\r
+\r
+ CpuFeaturesData = GetCpuFeaturesData();\r
\r
GetNumberOfProcessor (&NumberOfCpus, &NumberOfEnabledProcessors);\r
\r
//\r
// Wakeup all APs for data collection.\r
//\r
- StartupAPsWorker (CollectProcessorData);\r
+ StartupAPsWorker (CollectProcessorData, NULL);\r
\r
//\r
// Collect data on BSP\r
//\r
- CollectProcessorData (NULL);\r
+ CollectProcessorData (CpuFeaturesData);\r
\r
AnalysisProcessorFeatures (NumberOfCpus);\r
}\r
\r
-/**\r
- Performs CPU features Initialization.\r
-\r
- This service will invoke MP service to perform CPU features\r
- initialization on BSP/APs per user configuration.\r
-\r
- @note This service could be called by BSP only.\r
-**/\r
-VOID\r
-EFIAPI\r
-CpuFeaturesInitialize (\r
- VOID\r
- )\r
-{\r
- CPU_FEATURES_DATA *CpuFeaturesData;\r
- UINTN OldBspNumber;\r
-\r
- CpuFeaturesData = GetCpuFeaturesData ();\r
-\r
- OldBspNumber = GetProcessorIndex();\r
- CpuFeaturesData->BspNumber = OldBspNumber;\r
- //\r
- // Wakeup all APs for programming.\r
- //\r
- StartupAPsWorker (SetProcessorRegister);\r
- //\r
- // Programming BSP\r
- //\r
- SetProcessorRegister (NULL);\r
- //\r
- // Switch to new BSP if required\r
- //\r
- if (CpuFeaturesData->BspNumber != OldBspNumber) {\r
- SwitchNewBsp (CpuFeaturesData->BspNumber);\r
- }\r
-}\r