/** * * * * * @param[in,out] *mmPtr - Pointer to the MEM_MAIN_DATA_BLOCK * * @return TRUE - No fatal error occurs. * @return FALSE - Fatal error occurs. */ BOOLEAN MemMParallelTraining ( IN OUT MEM_MAIN_DATA_BLOCK *mmPtr ) { AMD_CONFIG_PARAMS *StdHeader; MEM_DATA_STRUCT *MemPtr; MEM_NB_BLOCK *NBPtr; DIE_INFO TrainInfo[MAX_NODES_SUPPORTED]; AP_DATA_TRANSFER ReturnData; AGESA_STATUS Status; UINT8 ApSts; UINT8 Die; UINT8 Socket; UINT32 Module; UINT32 LowCore; UINT32 HighCore; UINT32 Time; UINT32 TimeOut; UINT32 TargetApicId; BOOLEAN StillTraining; ALLOCATE_HEAP_PARAMS AllocHeapParams; UINT8 *BufferPtr; BOOLEAN TimeoutEn; NBPtr = mmPtr->NBPtr; MemPtr = mmPtr->MemPtr; StdHeader = &(mmPtr->MemPtr->StdHeader); Time = 0; TimeOut = PARALLEL_TRAINING_TIMEOUT; TimeoutEn = TRUE; IDS_TIMEOUT_CTL (&TimeoutEn); IDS_HDT_CONSOLE (MEM_STATUS, "\nStart parallel training\n"); AGESA_TESTPOINT (TpProcMemBeforeAnyTraining, StdHeader); // // Initialize Training Info Array // for (Die = 0; Die < mmPtr->DieCount; Die ++) { Socket = TrainInfo[Die].Socket = NBPtr[Die].MCTPtr->SocketId; Module = NBPtr[Die].MCTPtr->DieId; GetGivenModuleCoreRange (Socket, Module, &LowCore, &HighCore, StdHeader); TrainInfo[Die].Core = (UINT8) (LowCore & 0x000000FF); IDS_HDT_CONSOLE (MEM_FLOW, "\tLaunch core %d of socket %d\n", LowCore, Socket); TrainInfo[Die].Training = FALSE; } // // Start Training on Each remote die. // for (Die = 0; Die < mmPtr->DieCount; Die ++ ) { if (Die != BSP_DIE) { NBPtr[Die].BeforeDqsTraining (&(mmPtr->NBPtr[Die])); if (NBPtr[Die].MCTPtr->NodeMemSize != 0) { if (!NBPtr[Die].FeatPtr->Training (&(mmPtr->NBPtr[Die]))) { // Fail to launch code on AP PutEventLog (AGESA_ERROR, MEM_ERROR_PARALLEL_TRAINING_LAUNCH_FAIL, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader); SetMemError (AGESA_ERROR, NBPtr[Die].MCTPtr); MemPtr->ErrorHandling (NBPtr[Die].MCTPtr, EXCLUDE_ALL_DCT, EXCLUDE_ALL_CHIPSEL, &MemPtr->StdHeader); } else { TrainInfo[Die].Training = TRUE; } } } } // // Call training on BSP // IDS_HDT_CONSOLE (MEM_STATUS, "Node %d\n", NBPtr[BSP_DIE].Node); NBPtr[BSP_DIE].BeforeDqsTraining (&(mmPtr->NBPtr[BSP_DIE])); NBPtr[BSP_DIE].TrainingFlow (&(mmPtr->NBPtr[BSP_DIE])); NBPtr[BSP_DIE].AfterDqsTraining (&(mmPtr->NBPtr[BSP_DIE])); // // Get Results from remote processors training // do { StillTraining = FALSE; for (Die = 0; Die < mmPtr->DieCount; Die ++ ) { // // For each Die that is training, read the status // if (TrainInfo[Die].Training == TRUE) { GetLocalApicIdForCore (TrainInfo[Die].Socket, TrainInfo[Die].Core, &TargetApicId, StdHeader); ApSts = ApUtilReadRemoteControlByte (TargetApicId, StdHeader); if ((ApSts & 0x80) == 0) { // // Allocate buffer for received data // AllocHeapParams.RequestedBufferSize = ( sizeof (DIE_STRUCT) + NBPtr[Die].DctCount * ( sizeof (DCT_STRUCT) + ( NBPtr[Die].ChannelCount * ( sizeof (CH_DEF_STRUCT) + sizeof (MEM_PS_BLOCK) + ( (NBPtr[Die].MCTPtr->DctData[0].ChData[0].RowCount * NBPtr[Die].MCTPtr->DctData[0].ChData[0].ColumnCount * NUMBER_OF_DELAY_TABLES) + (MAX_BYTELANES_PER_CHANNEL * MAX_CS_PER_CHANNEL * NUMBER_OF_FAILURE_MASK_TABLES) ) ) ) ) ) + 3; AllocHeapParams.BufferHandle = GENERATE_MEM_HANDLE (ALLOC_PAR_TRN_HANDLE, Die, 0, 0); AllocHeapParams.Persist = HEAP_LOCAL_CACHE; if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) == AGESA_SUCCESS) { // // Receive Training Results // ReturnData.DataPtr = AllocHeapParams.BufferPtr; ReturnData.DataSizeInDwords = (UINT16) AllocHeapParams.RequestedBufferSize / 4; ReturnData.DataTransferFlags = 0; Status = ApUtilReceiveBuffer (TrainInfo[Die].Socket, TrainInfo[Die].Core, &ReturnData, StdHeader); if (Status != AGESA_SUCCESS) { SetMemError (Status, NBPtr[Die].MCTPtr); } BufferPtr = AllocHeapParams.BufferPtr; LibAmdMemCopy (NBPtr[Die].MCTPtr, BufferPtr, sizeof (DIE_STRUCT), StdHeader); BufferPtr += sizeof (DIE_STRUCT); LibAmdMemCopy ( NBPtr[Die].MCTPtr->DctData, BufferPtr, NBPtr[Die].DctCount * (sizeof (DCT_STRUCT) + NBPtr[Die].ChannelCount * sizeof (CH_DEF_STRUCT)), StdHeader); BufferPtr += NBPtr[Die].DctCount * (sizeof (DCT_STRUCT) + NBPtr[Die].ChannelCount * sizeof (CH_DEF_STRUCT)); LibAmdMemCopy ( NBPtr[Die].PSBlock, BufferPtr, NBPtr[Die].DctCount * NBPtr[Die].ChannelCount * sizeof (MEM_PS_BLOCK), StdHeader); BufferPtr += NBPtr[Die].DctCount * NBPtr[Die].ChannelCount * sizeof (MEM_PS_BLOCK); LibAmdMemCopy ( NBPtr[Die].MCTPtr->DctData[0].ChData[0].RcvEnDlys, BufferPtr, (NBPtr[Die].DctCount * NBPtr[Die].ChannelCount) * ((NBPtr[Die].MCTPtr->DctData[0].ChData[0].RowCount * NBPtr[Die].MCTPtr->DctData[0].ChData[0].ColumnCount * NUMBER_OF_DELAY_TABLES) + (MAX_BYTELANES_PER_CHANNEL * MAX_CS_PER_CHANNEL * NUMBER_OF_FAILURE_MASK_TABLES) ), StdHeader); HeapDeallocateBuffer (AllocHeapParams.BufferHandle, StdHeader); NBPtr[Die].AfterDqsTraining (&(mmPtr->NBPtr[Die])); TrainInfo[Die].Training = FALSE; } else { PutEventLog (AGESA_FATAL, MEM_ERROR_HEAP_ALLOCATE_FOR_RECEIVED_DATA, NBPtr[Die].Node, 0, 0, 0, StdHeader); SetMemError (AGESA_FATAL, NBPtr[Die].MCTPtr); ASSERT(FALSE); // Insufficient Heap Space allocation for parallel training buffer } } else if (ApSts == CORE_IDLE) { // AP does not have buffer to transmit to BSP // AP fails to locate a buffer for data transfer TrainInfo[Die].Training = FALSE; } else { // Signal to loop through again StillTraining = TRUE; } } } // Wait for 1 us MemUWait10ns (100, NBPtr->MemPtr); Time ++; } while ((StillTraining) && ((Time < TimeOut) || !TimeoutEn)); // Continue until all Dies are finished // if cannot finish in 1 s, do fatal exit if (StillTraining && TimeoutEn) { // Parallel training time out, do fatal exit, as there is at least one AP hangs. PutEventLog (AGESA_FATAL, MEM_ERROR_PARALLEL_TRAINING_TIME_OUT, 0, 0, 0, 0, &NBPtr->MemPtr->StdHeader); SetMemError (AGESA_FATAL, NBPtr[BSP_DIE].MCTPtr); ASSERT(FALSE); // Timeout occurred while still training } for (Die = 0; Die < mmPtr->DieCount; Die ++ ) { if (NBPtr[Die].MCTPtr->ErrCode == AGESA_FATAL) { return FALSE; } } return TRUE; }
/** * * Poll a bitfield. If the bitfield does not get set to the target value within * specified microseconds, it times out. * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK * @param[in] FieldName - Bit Field name * @param[in] Field - Value to be set * @param[in] MicroSecond - Number of microsecond to wait * @param[in] IfBroadCast - Need to broadcast to both DCT or not * * ---------------------------------------------------------------------------- */ VOID MemNPollBitFieldNb ( IN OUT MEM_NB_BLOCK *NBPtr, IN BIT_FIELD_NAME FieldName, IN UINT32 Field, IN UINT32 MicroSecond, IN BOOLEAN IfBroadCast ) { UINT8 ExcludeDCT; UINT16 ExcludeChipSelMask; UINT32 EventInfo; UINT64 InitTSC; UINT64 CurrentTSC; UINT64 TimeOut; AGESA_STATUS EventClass; MEM_DATA_STRUCT *MemPtr; DIE_STRUCT *MCTPtr; BOOLEAN TimeoutEn; MemPtr = NBPtr->MemPtr; MCTPtr = NBPtr->MCTPtr; ExcludeDCT = EXCLUDE_ALL_DCT; ExcludeChipSelMask = EXCLUDE_ALL_CHIPSEL; TimeoutEn = TRUE; IDS_TIMEOUT_CTL (&TimeoutEn); CurrentTSC = 0; LibAmdMsrRead (TSC, &InitTSC, &MemPtr->StdHeader); TimeOut = InitTSC + ((UINT64) MicroSecond * 1600); while ((CurrentTSC < TimeOut) || !TimeoutEn) { if (IfBroadCast) { if (NBPtr->BrdcstCheck (NBPtr, FieldName, Field)) { break; } } else { if (MemNGetBitFieldNb (NBPtr, FieldName) == Field) { break; } } LibAmdMsrRead (TSC, &CurrentTSC, &MemPtr->StdHeader); } if ((CurrentTSC >= TimeOut) && TimeoutEn) { // Default event class // If different event class is needed in one entry, override it. EventClass = AGESA_ERROR; switch (FieldName) { case BFDramEnabled: EventInfo = MEM_ERROR_DRAM_ENABLED_TIME_OUT; break; case BFDctAccessDone: EventInfo = MEM_ERROR_DCT_ACCESS_DONE_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFSendCtrlWord: EventInfo = MEM_ERROR_SEND_CTRL_WORD_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFPrefDramTrainMode: EventInfo = MEM_ERROR_PREF_DRAM_TRAIN_MODE_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFEnterSelfRef: EventInfo = MEM_ERROR_ENTER_SELF_REF_TIME_OUT; break; case BFFreqChgInProg: EventInfo = MEM_ERROR_FREQ_CHG_IN_PROG_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFExitSelfRef: EventInfo = MEM_ERROR_EXIT_SELF_REF_TIME_OUT; break; case BFSendMrsCmd: EventInfo = MEM_ERROR_SEND_MRS_CMD_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFSendZQCmd: EventInfo = MEM_ERROR_SEND_ZQ_CMD_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFDctExtraAccessDone: EventInfo = MEM_ERROR_DCT_EXTRA_ACCESS_DONE_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; case BFMemClrBusy: EventInfo = MEM_ERROR_MEM_CLR_BUSY_TIME_OUT; break; case BFMemCleared: EventInfo = MEM_ERROR_MEM_CLEARED_TIME_OUT; break; case BFFlushWr: EventInfo = MEM_ERROR_FLUSH_WR_TIME_OUT; ExcludeDCT = NBPtr->Dct; break; default: EventClass = 0; EventInfo = 0; IDS_ERROR_TRAP; } PutEventLog (EventClass, EventInfo, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &MemPtr->StdHeader); SetMemError (EventClass, MCTPtr); MemPtr->ErrorHandling (MCTPtr, ExcludeDCT, ExcludeChipSelMask, &MemPtr->StdHeader); } }