Cleanup MpService interface. Still needs more testing, but now it is much closer to PI spec.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11669 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
andrewfish 2011-05-17 03:48:27 +00:00
parent 5ec56d19a6
commit 8b6d0c057f
3 changed files with 159 additions and 46 deletions

View File

@ -109,6 +109,10 @@ typedef struct {
BOOLEAN SingleThread;
UINTN StartedNumber;
PROCESSOR_DATA_BLOCK *ProcessorData;
UINTN Timeout;
UINTN *FailedList;
UINTN FailedListIndex;
BOOLEAN TimeoutActive;
} MP_SYSTEM_DATA;

View File

@ -402,10 +402,13 @@ CpuMpServicesStartupAllAps (
if (FailedCpuList != NULL) {
FailledList = AllocatePool ((gMPSystem.NumberOfProcessors + 1) * sizeof (UINTN));
SetMemN (FailledList, (gMPSystem.NumberOfProcessors + 1) * sizeof (UINTN), END_OF_CPU_LIST);
FailedListIndex = 0;
*FailedCpuList = FailledList;
gMPSystem.FailedList = AllocatePool ((gMPSystem.NumberOfProcessors + 1) * sizeof (UINTN));
if (gMPSystem.FailedList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
SetMemN (gMPSystem.FailedList, (gMPSystem.NumberOfProcessors + 1) * sizeof (UINTN), END_OF_CPU_LIST);
gMPSystem.FailedListIndex = 0;
*FailedCpuList = gMPSystem.FailedList;
}
Timeout = TimeoutInMicroseconds;
@ -415,6 +418,7 @@ CpuMpServicesStartupAllAps (
gMPSystem.FinishCount = 0;
gMPSystem.StartCount = 0;
gMPSystem.SingleThread = SingleThread;
APInitialState = CPU_STATE_READY;
for (Number = 0; Number < gMPSystem.NumberOfProcessors; Number++) {
@ -425,6 +429,12 @@ CpuMpServicesStartupAllAps (
continue;
}
if ((ProcessorData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) == 0) {
// Skip Disabled processors
gMPSystem.FailedList[gMPSystem.FailedListIndex++] = Number;
continue;
}
//
// Get APs prepared, and put failing APs into FailedCpuList
// if "SingleThread", only 1 AP will put to ready state, other AP will be put to ready
@ -441,18 +451,42 @@ CpuMpServicesStartupAllAps (
if (SingleThread) {
APInitialState = CPU_STATE_BLOCKED;
}
} else if (FailedCpuList != NULL) {
FailledList[FailedListIndex++] = Number;
ListIndex++;
} else {
return EFI_NOT_READY;
}
}
if (FailedCpuList != NULL) {
if (FailedListIndex == 0) {
FreePool (*FailedCpuList);
*FailedCpuList = NULL;
if (WaitEvent != NULL) {
for (Number = 0; Number < gMPSystem.NumberOfProcessors; Number++) {
ProcessorData = &gMPSystem.ProcessorData[Number];
if ((ProcessorData->Info.StatusFlag & PROCESSOR_AS_BSP_BIT) == PROCESSOR_AS_BSP_BIT) {
// Skip BSP
continue;
}
if ((ProcessorData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) == 0) {
// Skip Disabled processors
continue;
}
SetApProcedure (ProcessorData, Procedure, ProcedureArgument);
}
//
// Save data into private data structure, and create timer to poll AP state before exiting
//
gMPSystem.Procedure = Procedure;
gMPSystem.ProcedureArgument = ProcedureArgument;
gMPSystem.WaitEvent = WaitEvent;
gMPSystem.Timeout = TimeoutInMicroseconds;
gMPSystem.TimeoutActive = (BOOLEAN)(TimeoutInMicroseconds != 0);
Status = gBS->SetTimer (
gMPSystem.CheckAllAPsEvent,
TimerPeriodic,
gPollInterval
);
return Status;
}
while (TRUE) {
@ -463,6 +497,11 @@ CpuMpServicesStartupAllAps (
continue;
}
if ((ProcessorData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) == 0) {
// Skip Disabled processors
continue;
}
gThread->MutexLock (ProcessorData->StateLock);
ProcessorState = ProcessorData->State;
gThread->MutexUnlock (ProcessorData->StateLock);
@ -490,29 +529,27 @@ CpuMpServicesStartupAllAps (
}
if (gMPSystem.FinishCount == gMPSystem.StartCount) {
return EFI_SUCCESS;
Status = EFI_SUCCESS;
goto Done;
}
if ((TimeoutInMicroseconds != 0) && (Timeout < 0)) {
//
// Save data into private data structure, and create timer to poll AP state before exiting
//
gMPSystem.Procedure = Procedure;
gMPSystem.ProcedureArgument = ProcedureArgument;
gMPSystem.WaitEvent = WaitEvent;
Status = gBS->SetTimer (
gMPSystem.CheckAllAPsEvent,
TimerPeriodic,
gPollInterval
);
return EFI_TIMEOUT;
Status = EFI_TIMEOUT;
goto Done;
}
gBS->Stall (gPollInterval);
Timeout -= gPollInterval;
}
Done:
if (FailedCpuList != NULL) {
if (gMPSystem.FailedListIndex == 0) {
FreePool (*FailedCpuList);
*FailedCpuList = NULL;
}
}
return EFI_SUCCESS;
}
@ -649,6 +686,18 @@ CpuMpServicesStartupThisAP (
SetApProcedure (&gMPSystem.ProcessorData[ProcessorNumber], Procedure, ProcedureArgument);
if (WaitEvent != NULL) {
// Non Blocking
gMPSystem.WaitEvent = WaitEvent;
Status = gBS->SetTimer (
gMPSystem.ProcessorData[ProcessorNumber].CheckThisAPEvent,
TimerPeriodic,
gPollInterval
);
return EFI_SUCCESS;
}
// Blocking
while (TRUE) {
gThread->MutexLock (&gMPSystem.ProcessorData[ProcessorNumber].StateLock);
if (gMPSystem.ProcessorData[ProcessorNumber].State == CPU_STATE_FINISHED) {
@ -660,12 +709,6 @@ CpuMpServicesStartupThisAP (
gThread->MutexUnlock (&gMPSystem.ProcessorData[ProcessorNumber].StateLock);
if ((TimeoutInMicroseconds != 0) && (Timeout < 0)) {
gMPSystem.WaitEvent = WaitEvent;
Status = gBS->SetTimer (
gMPSystem.ProcessorData[ProcessorNumber].CheckThisAPEvent,
TimerPeriodic,
gPollInterval
);
return EFI_TIMEOUT;
}
@ -929,6 +972,12 @@ CpuCheckAllAPsStatus (
PROCESSOR_DATA_BLOCK *NextData;
EFI_STATUS Status;
PROCESSOR_STATE ProcessorState;
UINTN Cpu;
BOOLEAN Found;
if (gMPSystem.TimeoutActive) {
gMPSystem.Timeout -= gPollInterval;
}
ProcessorData = (PROCESSOR_DATA_BLOCK *) Context;
@ -938,6 +987,11 @@ CpuCheckAllAPsStatus (
continue;
}
if ((ProcessorData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) == 0) {
// Skip Disabled processors
continue;
}
// This is an Interrupt Service routine.
// This can grab a lock that is held in a non-interrupt
// context. Meaning deadlock. Which is a bad thing.
@ -978,14 +1032,69 @@ CpuCheckAllAPsStatus (
}
}
if (gMPSystem.FinishCount == gMPSystem.StartCount) {
if (gMPSystem.TimeoutActive && gMPSystem.Timeout < 0) {
//
// Timeout
//
if (gMPSystem.FailedList != NULL) {
for (ProcessorNumber = 0; ProcessorNumber < gMPSystem.NumberOfProcessors; ProcessorNumber++) {
if ((ProcessorData[ProcessorNumber].Info.StatusFlag & PROCESSOR_AS_BSP_BIT) == PROCESSOR_AS_BSP_BIT) {
// Skip BSP
continue;
}
if ((ProcessorData->Info.StatusFlag & PROCESSOR_ENABLED_BIT) == 0) {
// Skip Disabled processors
continue;
}
// Mark the
Status = gThread->MutexTryLock (gMPSystem.ProcessorData[ProcessorNumber].StateLock);
if (EFI_ERROR(Status)) {
return;
}
ProcessorState = gMPSystem.ProcessorData[ProcessorNumber].State;
gThread->MutexUnlock (gMPSystem.ProcessorData[ProcessorNumber].StateLock);
if (ProcessorState != CPU_STATE_IDLE) {
// If we are retrying make sure we don't double count
for (Cpu = 0, Found = FALSE; Cpu < gMPSystem.NumberOfProcessors; Cpu++) {
if (gMPSystem.FailedList[Cpu] == END_OF_CPU_LIST) {
break;
}
if (gMPSystem.FailedList[ProcessorNumber] == Cpu) {
Found = TRUE;
break;
}
}
if (!Found) {
gMPSystem.FailedList[gMPSystem.FailedListIndex++] = Cpu;
}
}
}
}
// Force terminal exit
gMPSystem.FinishCount = gMPSystem.StartCount;
}
if (gMPSystem.FinishCount != gMPSystem.StartCount) {
return;
}
gBS->SetTimer (
gMPSystem.CheckAllAPsEvent,
TimerCancel,
0
);
Status = gBS->SignalEvent (gMPSystem.WaitEvent);
if (gMPSystem.FailedListIndex == 0) {
if (gMPSystem.FailedList != NULL) {
FreePool (gMPSystem.FailedList);
gMPSystem.FailedList = NULL;
}
}
Status = gBS->SignalEvent (gMPSystem.WaitEvent);
return ;
}
@ -1004,8 +1113,8 @@ CpuCheckThisAPStatus (
ProcessorData = (PROCESSOR_DATA_BLOCK *) Context;
//
// rdar://6260979 - This is an Interrupt Service routine.
// this can grab a lock that is held in a non-interrupt
// This is an Interrupt Service routine.
// that can grab a lock that is held in a non-interrupt
// context. Meaning deadlock. Which is a badddd thing.
// So, try lock it. If we can get it, cool, do our thing.
// otherwise, just dump out & try again on the next iteration.

View File

@ -218,7 +218,7 @@
#define BOOT_IN_RECOVERY_MODE 0x20
gInOsEmuPkgTokenSpaceGuid.PcdEmuBootMode|0
gInOsEmuPkgTokenSpaceGuid.PcdEmuApCount|L"0"
gInOsEmuPkgTokenSpaceGuid.PcdEmuApCount|L"1"
gInOsEmuPkgTokenSpaceGuid.PcdEmuPhysicalDisk|L"E:RW;245760;512"
gInOsEmuPkgTokenSpaceGuid.PcdEmuVirtualDisk|L"FW;40960;512"