From: "Nate DeSimone" <nathaniel.l.desimone@intel.com>
To: devel@edk2.groups.io
Cc: Isaac Oram <isaac.w.oram@intel.com>,
Sai Chaganty <rangasai.v.chaganty@intel.com>,
Liming Gao <gaoliming@byosoft.com.cn>,
Michael Kubacki <michael.kubacki@microsoft.com>
Subject: [edk2-platforms] [PATCH v1 5/9] IpmiFeaturePkg: Add GenericIpmi PEIM
Date: Mon, 1 Mar 2021 18:28:00 -0800 [thread overview]
Message-ID: <20210302022804.8641-6-nathaniel.l.desimone@intel.com> (raw)
In-Reply-To: <20210302022804.8641-1-nathaniel.l.desimone@intel.com>
From: Isaac Oram <isaac.w.oram@intel.com>
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3242
Adds the PEI version of the generic
IPMI transport driver.
Cc: Sai Chaganty <rangasai.v.chaganty@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael Kubacki <michael.kubacki@microsoft.com>
Signed-off-by: Isaac Oram <isaac.w.oram@intel.com>
Co-authored-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
---
.../GenericIpmi/Pei/PeiGenericIpmi.c | 362 ++++++++++++++++++
.../GenericIpmi/Pei/PeiGenericIpmi.h | 138 +++++++
.../GenericIpmi/Pei/PeiGenericIpmi.inf | 58 +++
.../GenericIpmi/Pei/PeiIpmiBmc.c | 277 ++++++++++++++
.../GenericIpmi/Pei/PeiIpmiBmc.h | 38 ++
.../GenericIpmi/Pei/PeiIpmiBmcDef.h | 156 ++++++++
6 files changed, 1029 insertions(+)
create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.c
create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.h
create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.inf
create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.c
create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.h
create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmcDef.h
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.c
new file mode 100644
index 0000000000..31f613925d
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.c
@@ -0,0 +1,362 @@
+/** @file
+ Generic IPMI stack during PEI phase
+
+ @copyright
+ Copyright 2017 - 2021 Intel Corporation. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <IndustryStandard/Ipmi.h>
+#include "PeiGenericIpmi.h"
+#include <Library/ReportStatusCodeLib.h>
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Function Implementations
+//
+
+/*****************************************************************************
+ @brief
+ Internal function
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS Always return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+PeiInitializeIpmiKcsPhysicalLayer (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ PEI_IPMI_BMC_INSTANCE_DATA *mIpmiInstance;
+
+ mIpmiInstance = NULL;
+
+ //
+ // Send Pre-Boot signal to BMC
+ //
+ if (PcdGetBool (PcdSignalPreBootToBmc)) {
+ Status = SendPreBootSignaltoBmc (PeiServices);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Enable OEM specific southbridge SIO KCS I/O address range 0xCA0 to 0xCAF at here
+ // if the the I/O address range has not been enabled.
+ //
+
+ mIpmiInstance = AllocateZeroPool (sizeof (PEI_IPMI_BMC_INSTANCE_DATA));
+ if (mIpmiInstance == NULL) {
+ DEBUG ((EFI_D_ERROR,"IPMI Peim:EFI_OUT_OF_RESOURCES of memory allocation\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Calibrate TSC Counter. Stall for 10ms, then multiply the resulting number of
+ // ticks in that period by 100 to get the number of ticks in a 1 second timeout
+ //
+ DEBUG ((DEBUG_INFO,"IPMI Peim:IPMI STACK Initialization\n"));
+ mIpmiInstance->KcsTimeoutPeriod = (BMC_KCS_TIMEOUT_PEI *1000*1000) / KCS_DELAY_UNIT_PEI;
+ DEBUG ((EFI_D_INFO,"IPMI Peim:KcsTimeoutPeriod = 0x%x\n", mIpmiInstance->KcsTimeoutPeriod));
+
+ //
+ // Initialize IPMI IO Base.
+ //
+ mIpmiInstance->IpmiIoBase = PcdGet16 (PcdIpmiIoBaseAddress);
+ DEBUG ((EFI_D_INFO,"IPMI Peim:IpmiIoBase=0x%x\n",mIpmiInstance->IpmiIoBase));
+ mIpmiInstance->Signature = SM_IPMI_BMC_SIGNATURE;
+ mIpmiInstance->SlaveAddress = BMC_SLAVE_ADDRESS;
+ mIpmiInstance->BmcStatus = BMC_NOTREADY;
+ mIpmiInstance->IpmiTransportPpi.IpmiSubmitCommand = PeiIpmiSendCommand;
+ mIpmiInstance->IpmiTransportPpi.GetBmcStatus = PeiGetIpmiBmcStatus;
+
+ mIpmiInstance->PeiIpmiBmcDataDesc.Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
+ mIpmiInstance->PeiIpmiBmcDataDesc.Guid = &gPeiIpmiTransportPpiGuid;
+ mIpmiInstance->PeiIpmiBmcDataDesc.Ppi = &mIpmiInstance->IpmiTransportPpi;
+
+ //
+ // Get the Device ID and check if the system is in Force Update mode.
+ //
+ Status = GetDeviceId (mIpmiInstance);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR,"IPMI Peim:Get BMC Device Id Failed. Status=%r\n",Status));
+ }
+
+ //
+ // Do not continue initialization if the BMC is in Force Update Mode.
+ //
+ if (mIpmiInstance->BmcStatus == BMC_UPDATE_IN_PROGRESS || mIpmiInstance->BmcStatus == BMC_HARDFAIL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Just produce PPI
+ //
+ Status = PeiServicesInstallPpi (&mIpmiInstance->PeiIpmiBmcDataDesc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/*****************************************************************************
+ @bref
+ PRE-BOOT signal will be sent in very early PEI phase, to enable necessary KCS access for host boot.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS Indicates that the signal is sent successfully.
+**/
+EFI_STATUS
+SendPreBootSignaltoBmc (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_CPU_IO_PPI *CpuIoPpi;
+ UINT32 ProvisionPort = 0;
+ UINT8 PreBoot = 0;
+
+ //
+ // Locate CpuIo service
+ //
+ CpuIoPpi = (**PeiServices).CpuIo;
+ ProvisionPort = PcdGet32 (PcdSioMailboxBaseAddress) + MBXDAT_B;
+ PreBoot = 0x01;// PRE-BOOT
+
+ Status = CpuIoPpi->Io.Write (
+ PeiServices,
+ CpuIoPpi,
+ EfiPeiCpuIoWidthUint8,
+ ProvisionPort,
+ 1,
+ &PreBoot
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SendPreBootSignaltoBmc () Write PRE-BOOT Status=%r\n", Status));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/*****************************************************************************
+ @bref
+ The entry point of the Ipmi PEIM. Instals Ipmi PPI interface.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS Indicates that Ipmi initialization completed successfully.
+**/
+EFI_STATUS
+PeimIpmiInterfaceInit (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+
+ //
+ // Performing Ipmi KCS physical layer initialization
+ //
+ Status = PeiInitializeIpmiKcsPhysicalLayer (PeiServices);
+
+ return EFI_SUCCESS;
+} // PeimIpmiInterfaceInit()
+
+
+EFI_STATUS
+PeiIpmiSendCommand (
+ IN PEI_IPMI_TRANSPORT_PPI *This,
+ IN UINT8 NetFunction,
+ IN UINT8 Lun,
+ IN UINT8 Command,
+ IN UINT8 *CommandData,
+ IN UINT32 CommandDataSize,
+ IN OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ )
+/*++
+
+Routine Description:
+
+ Send Ipmi Command in the right mode: HECI or KCS, to the
+ appropiate device, ME or BMC.
+
+Arguments:
+
+ This - Pointer to IPMI protocol instance
+ NetFunction - Net Function of command to send
+ Lun - LUN of command to send
+ Command - IPMI command to send
+ CommandData - Pointer to command data buffer, if needed
+ CommandDataSize - Size of command data buffer
+ ResponseData - Pointer to response data buffer
+ ResponseDataSize - Pointer to response data buffer size
+
+Returns:
+
+ EFI_INVALID_PARAMETER - One of the input values is bad
+ EFI_DEVICE_ERROR - IPMI command failed
+ EFI_BUFFER_TOO_SMALL - Response buffer is too small
+ EFI_UNSUPPORTED - Command is not supported by BMC
+ EFI_SUCCESS - Command completed successfully
+
+--*/
+{
+ //
+ // This Will be unchanged ( BMC/KCS style )
+ //
+ return PeiIpmiSendCommandToBmc (
+ This,
+ NetFunction,
+ Lun,
+ Command,
+ CommandData,
+ (UINT8) CommandDataSize,
+ ResponseData,
+ (UINT8 *) ResponseDataSize,
+ NULL
+ );
+} // IpmiSendCommand()
+
+EFI_STATUS
+PeiGetIpmiBmcStatus (
+ IN PEI_IPMI_TRANSPORT_PPI *This,
+ OUT BMC_STATUS *BmcStatus,
+ OUT SM_COM_ADDRESS *ComAddress
+ )
+/*++
+
+Routine Description:
+
+ Updates the BMC status and returns the Com Address
+
+Arguments:
+
+ This - Pointer to IPMI protocol instance
+ BmcStatus - BMC status
+ ComAddress - Com Address
+
+Returns:
+
+ EFI_SUCCESS - Success
+
+--*/
+{
+ return PeiIpmiBmcStatus (
+ This,
+ BmcStatus,
+ ComAddress,
+ NULL
+ );
+}
+
+
+EFI_STATUS
+GetDeviceId (
+ IN PEI_IPMI_BMC_INSTANCE_DATA *mIpmiInstance
+ )
+/*++
+
+Routine Description:
+ Execute the Get Device ID command to determine whether or not the BMC is in Force Update
+ Mode. If it is, then report it to the error manager.
+
+Arguments:
+ mIpmiInstance - Data structure describing BMC variables and used for sending commands
+ StatusCodeValue - An array used to accumulate error codes for later reporting.
+ ErrorCount - Counter used to keep track of error codes in StatusCodeValue
+
+Returns:
+ Status
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT32 DataSize;
+ SM_CTRL_INFO *pBmcInfo;
+ UINTN Retries;
+
+ //
+ // Set up a loop to retry for up to PcdIpmiBmcReadyDelayTimer seconds. Calculate retries not timeout
+ // so that in case KCS is not enabled and IpmiSendCommand() returns
+ // immediately we will not wait all the PcdIpmiBmcReadyDelayTimer seconds.
+ //
+ Retries = PcdGet8 (PcdIpmiBmcReadyDelayTimer);
+ //
+ // Get the device ID information for the BMC.
+ //
+ DataSize = sizeof (mIpmiInstance->TempData);
+ while (EFI_ERROR (Status = PeiIpmiSendCommand (
+ &mIpmiInstance->IpmiTransportPpi,
+ IPMI_NETFN_APP,
+ 0,
+ IPMI_APP_GET_DEVICE_ID,
+ NULL,
+ 0,
+ mIpmiInstance->TempData,
+ &DataSize
+ ))) {
+ DEBUG ((EFI_D_ERROR, "[IPMI] BMC does not respond (status: %r), %d retries left\n",
+ Status, Retries));
+
+ if (Retries-- == 0) {
+ ReportStatusCode (EFI_ERROR_CODE | EFI_ERROR_MAJOR, EFI_COMPUTING_UNIT_FIRMWARE_PROCESSOR | EFI_CU_FP_EC_COMM_ERROR);
+ mIpmiInstance->BmcStatus = BMC_HARDFAIL;
+ return Status;
+ }
+ //
+ // Handle the case that BMC FW still not enable KCS channel after AC cycle. just stall 1 second
+ //
+ MicroSecondDelay (1*1000*1000);
+ }
+ pBmcInfo = (SM_CTRL_INFO*) &mIpmiInstance->TempData[0];
+ DEBUG ((DEBUG_INFO, "[IPMI PEI] BMC Device ID: 0x%02X, firmware version: %d.%02X UpdateMode:%x\n",
+ pBmcInfo->DeviceId, pBmcInfo->MajorFirmwareRev, pBmcInfo->MinorFirmwareRev, pBmcInfo->UpdateMode));
+ //
+ // In OpenBMC, UpdateMode: the bit 7 of byte 4 in get device id command is used for the BMC status:
+ // 0 means BMC is ready, 1 means BMC is not ready.
+ // At the very beginning of BMC power on, the status is 1 means BMC is in booting process and not ready. It is not the flag for force update mode.
+ //
+ if (pBmcInfo->UpdateMode == BMC_READY) {
+ mIpmiInstance->BmcStatus = BMC_OK;
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Updatemode = 1 mean BMC is not ready, continue waiting.
+ //
+ while (Retries-- != 0) {
+ MicroSecondDelay(1*1000*1000); //delay 1 seconds
+ DEBUG ((DEBUG_INFO, "[IPMI PEI] UpdateMode Retries:%x \n",Retries));
+ Status = PeiIpmiSendCommand (
+ &mIpmiInstance->IpmiTransportPpi,
+ IPMI_NETFN_APP,
+ 0,
+ IPMI_APP_GET_DEVICE_ID,
+ NULL,
+ 0,
+ mIpmiInstance->TempData,
+ &DataSize
+ );
+ if (!EFI_ERROR (Status)) {
+ pBmcInfo = (SM_CTRL_INFO*) &mIpmiInstance->TempData[0];
+ DEBUG ((DEBUG_INFO, "[IPMI PEI] UpdateMode Retries:%x pBmcInfo->UpdateMode:%x\n", Retries, pBmcInfo->UpdateMode));
+ if (pBmcInfo->UpdateMode == BMC_READY) {
+ mIpmiInstance->BmcStatus = BMC_OK;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ mIpmiInstance->BmcStatus = BMC_HARDFAIL;
+ return Status;
+} // GetDeviceId()
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.h
new file mode 100644
index 0000000000..d31af85325
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.h
@@ -0,0 +1,138 @@
+/** @file
+ Generic IPMI stack head file during PEI phase
+
+ @copyright
+ Copyright 2017 - 2021 Intel Corporation. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PEI_IPMI_INIT_H_
+#define _PEI_IPMI_INIT_H_
+
+#include <PiPei.h>
+#include <Uefi.h>
+
+#include <Ppi/IpmiTransportPpi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PciLib.h>
+
+#include "PeiIpmiBmcDef.h"
+#include "PeiIpmiBmc.h"
+
+//
+// Prototypes
+//
+#define MBXDAT_B 0x0B
+#define BMC_KCS_TIMEOUT_PEI 5 // [s] Single KSC request timeout
+#define KCS_DELAY_UNIT_PEI 1000 // [s] Each KSC IO delay
+#define IPMI_DEFAULT_IO_BASE 0xCA2
+
+//
+// Internal(hook) function list
+//
+EFI_STATUS
+SendPreBootSignaltoBmc (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+ /*++
+
+Routine Description:
+ Send Pre-Boot signal to BMC
+
+Arguments:
+ PeiServices - General purpose services available to every PEIM.
+
+Returns:
+ EFI_SUCCESS - Success
+--*/
+;
+
+EFI_STATUS
+PeiIpmiSendCommand (
+ IN PEI_IPMI_TRANSPORT_PPI *This,
+ IN UINT8 NetFunction,
+ IN UINT8 Lun,
+ IN UINT8 Command,
+ IN UINT8 *CommandData,
+ IN UINT32 CommandDataSize,
+ IN OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ )
+/*++
+
+Routine Description:
+ Send IPMI command to BMC
+
+Arguments:
+ This - Pointer to IPMI protocol instance
+ NetFunction - Net Function of command to send
+ Lun - LUN of command to send
+ Command - IPMI command to send
+ CommandData - Pointer to command data buffer, if needed
+ CommandDataSize - Size of command data buffer
+ ResponseData - Pointer to response data buffer
+ ResponseDataSize - Pointer to response data buffer size
+
+Returns:
+ EFI_INVALID_PARAMETER - One of the input values is bad
+ EFI_DEVICE_ERROR - IPMI command failed
+ EFI_BUFFER_TOO_SMALL - Response buffer is too small
+ EFI_UNSUPPORTED - Command is not supported by BMC
+ EFI_SUCCESS - Command completed successfully
+--*/
+;
+
+EFI_STATUS
+PeiGetIpmiBmcStatus (
+ IN PEI_IPMI_TRANSPORT_PPI *This,
+ OUT BMC_STATUS *BmcStatus,
+ OUT SM_COM_ADDRESS *ComAddress
+ )
+/*++
+
+Routine Description:
+ Updates the BMC status and returns the Com Address
+
+Arguments:
+ This - Pointer to IPMI protocol instance
+ BmcStatus - BMC status
+ ComAddress - Com Address
+
+Returns:
+ EFI_SUCCESS - Success
+--*/
+;
+
+//
+// internal function list
+//
+EFI_STATUS
+GetDeviceId (
+ IN PEI_IPMI_BMC_INSTANCE_DATA *mIpmiInstance
+ )
+/*++
+
+Routine Description:
+ Execute the Get Device ID command to determine whether or not the BMC is in Force Update
+ Mode. If it is, then report it to the error manager.
+
+Arguments:
+ mIpmiInstance - Data structure describing BMC variables and used for sending commands
+ StatusCodeValue - An array used to accumulate error codes for later reporting.
+ ErrorCount - Counter used to keep track of error codes in StatusCodeValue
+
+Returns:
+ Status
+
+--*/
+;
+#endif //_PEI_IPMI_INIT_H_
+
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.inf
new file mode 100644
index 0000000000..0ef2c18116
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.inf
@@ -0,0 +1,58 @@
+## @file
+# Generic IPMI during PEI phase
+#
+# @copyright
+# Copyright 2017 - 2021 Intel Corporation. <BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiGenericIpmi
+ FILE_GUID = 0B161208-2958-460C-B97F-B912A8AD0F8D
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PeimIpmiInterfaceInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+# HOB Guid C Name: gEfiHtBistHobGuid Hob Type: GUID_EXTENSION
+#
+[Sources]
+ ../Common/IpmiBmcCommon.h
+ ../Common/KcsBmc.c
+ ../Common/KcsBmc.h
+ PeiIpmiBmc.c
+ PeiIpmiBmc.h
+ PeiIpmiBmcDef.h
+ PeiGenericIpmi.c
+ PeiGenericIpmi.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ PciLib
+ MemoryAllocationLib
+ DebugLib
+ IoLib
+ TimerLib
+
+[Guids]
+
+[Ppis]
+ gPeiIpmiTransportPpiGuid #ALWAYS PRODUCE
+
+[Pcd]
+ gIpmiFeaturePkgTokenSpaceGuid.PcdIpmiIoBaseAddress
+ gIpmiFeaturePkgTokenSpaceGuid.PcdIpmiBmcReadyDelayTimer
+ gIpmiFeaturePkgTokenSpaceGuid.PcdSioMailboxBaseAddress
+ gIpmiFeaturePkgTokenSpaceGuid.PcdSignalPreBootToBmc
+
+[Depex]
+ TRUE
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.c
new file mode 100644
index 0000000000..32665b3e22
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.c
@@ -0,0 +1,277 @@
+/** @file
+ Generic IPMI transport layer during PEI phase
+
+ @copyright
+ Copyright 2016 - 2021 Intel Corporation. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "PeiIpmiBmc.h"
+
+EFI_STATUS
+UpdateErrorStatus (
+ IN UINT8 BmcError,
+ PEI_IPMI_BMC_INSTANCE_DATA *IpmiInstance
+ )
+/*++
+
+Routine Description:
+
+ Check if the completion code is a Soft Error and increment the count. The count
+ is not updated if the BMC is in Force Update Mode.
+
+Arguments:
+
+ BmcError - Completion code to check
+ IpmiInstance - BMC instance data
+
+Returns:
+
+ EFI_SUCCESS - Status
+
+--*/
+{
+ UINT8 Errors[] = COMPLETION_CODES;
+ UINT16 CodeCount;
+ UINT8 i;
+
+ CodeCount = sizeof (Errors) / sizeof (Errors[0]);
+ for (i = 0; i < CodeCount; i++) {
+ if (BmcError == Errors[i]) {
+ //
+ // Don't change Bmc Status flag if the BMC is in Force Update Mode.
+ //
+ if (IpmiInstance->BmcStatus != BMC_UPDATE_IN_PROGRESS) {
+ IpmiInstance->BmcStatus = BMC_SOFTFAIL;
+ }
+
+ IpmiInstance->SoftErrorCount++;
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PeiIpmiSendCommandToBmc (
+ IN PEI_IPMI_TRANSPORT_PPI *This,
+ IN UINT8 NetFunction,
+ IN UINT8 Lun,
+ IN UINT8 Command,
+ IN UINT8 *CommandData,
+ IN UINT8 CommandDataSize,
+ IN OUT UINT8 *ResponseData,
+ IN OUT UINT8 *ResponseDataSize,
+ IN VOID *Context
+ )
+/*++
+
+Routine Description:
+
+ Send IPMI command to BMC
+
+Arguments:
+
+ This - Pointer to IPMI protocol instance
+ NetFunction - Net Function of command to send
+ Lun - LUN of command to send
+ Command - IPMI command to send
+ CommandData - Pointer to command data buffer, if needed
+ CommandDataSize - Size of command data buffer
+ ResponseData - Pointer to response data buffer
+ ResponseDataSize - Pointer to response data buffer size
+ Context - Context
+
+Returns:
+
+ EFI_INVALID_PARAMETER - One of the input values is bad
+ EFI_DEVICE_ERROR - IPMI command failed
+ EFI_BUFFER_TOO_SMALL - Response buffer is too small
+ EFI_UNSUPPORTED - Command is not supported by BMC
+ EFI_SUCCESS - Command completed successfully
+
+--*/
+{
+ PEI_IPMI_BMC_INSTANCE_DATA *IpmiInstance;
+ UINT8 DataSize;
+ EFI_STATUS Status;
+ IPMI_COMMAND *IpmiCommand;
+ IPMI_RESPONSE *IpmiResponse;
+ UINT8 Index;
+
+ IpmiInstance = INSTANCE_FROM_PEI_SM_IPMI_BMC_THIS (This);
+
+ //
+ // The TempData buffer is used for both sending command data and receiving
+ // response data. Since the command format is different from the response
+ // format, the buffer is cast to both structure definitions.
+ //
+ IpmiCommand = (IPMI_COMMAND*) IpmiInstance->TempData;
+ IpmiResponse = (IPMI_RESPONSE*) IpmiInstance->TempData;
+
+ //
+ // Send IPMI command to BMC
+ //
+ IpmiCommand->Lun = Lun;
+ IpmiCommand->NetFunction = NetFunction;
+ IpmiCommand->Command = Command;
+
+ //
+ // Ensure that the buffer is valid before attempting to copy the command data
+ // buffer into the IpmiCommand structure.
+ //
+ if (CommandDataSize > 0) {
+ if (CommandData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (
+ IpmiCommand->CommandData,
+ CommandData,
+ CommandDataSize
+ );
+ }
+
+ Status = SendDataToBmcPort (
+ IpmiInstance->KcsTimeoutPeriod,
+ IpmiInstance->IpmiIoBase,
+ Context,
+ (UINT8 *) IpmiCommand,
+ (CommandDataSize + IPMI_COMMAND_HEADER_SIZE)
+ );
+
+ if (Status != EFI_SUCCESS) {
+ IpmiInstance->BmcStatus = BMC_SOFTFAIL;
+ IpmiInstance->SoftErrorCount++;
+ DEBUG ((EFI_D_ERROR, "PEI Phase SendDataToBmcPort failed Status:%r\n", Status));
+ return Status;
+ }
+
+ //
+ // Get Response to IPMI Command from BMC.
+ //
+ DataSize = MAX_TEMP_DATA;
+ Status = ReceiveBmcDataFromPort (
+ IpmiInstance->KcsTimeoutPeriod,
+ IpmiInstance->IpmiIoBase,
+ Context,
+ (UINT8 *) IpmiResponse,
+ &DataSize
+ );
+
+ if (Status != EFI_SUCCESS) {
+ IpmiInstance->BmcStatus = BMC_SOFTFAIL;
+ IpmiInstance->SoftErrorCount++;
+ DEBUG ((EFI_D_ERROR, "PEI Phase ReceiveBmcDataFromPort failed Status:%r\n", Status));
+ return Status;
+ }
+
+ if ((IpmiResponse->CompletionCode != COMP_CODE_NORMAL) &&
+ (IpmiInstance->BmcStatus == BMC_UPDATE_IN_PROGRESS)) {
+ //
+ // If the completion code is not normal and the BMC is in Force Update
+ // mode, then update the error status and return EFI_UNSUPPORTED.
+ //
+ UpdateErrorStatus (
+ IpmiResponse->CompletionCode,
+ IpmiInstance
+ );
+ return EFI_UNSUPPORTED;
+ } else if (IpmiResponse->CompletionCode != COMP_CODE_NORMAL) {
+ //
+ // Otherwise if the BMC is in normal mode, but the completion code
+ // is not normal, then update the error status and return device error.
+ //
+ UpdateErrorStatus (
+ IpmiResponse->CompletionCode,
+ IpmiInstance
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If we got this far without any error codes, but the DataSize is 0 then the
+ // command response failed, so do not continue.
+ //
+ //
+ // Some abnormal case, in order to avoid that BMC sent illegal data size.
+ // If we got this far without any error codes, but the DataSize less than IPMI_RESPONSE_HEADER_SIZE, then the
+ // command response failed, so do not continue.
+ if (DataSize < IPMI_RESPONSE_HEADER_SIZE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Verify the response data buffer passed in is big enough.
+ //
+ if ((DataSize - IPMI_RESPONSE_HEADER_SIZE) > *ResponseDataSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Copy data over to the response data buffer.
+ //
+ *ResponseDataSize = DataSize - IPMI_RESPONSE_HEADER_SIZE;
+ CopyMem (
+ ResponseData,
+ IpmiResponse->ResponseData,
+ *ResponseDataSize
+ );
+
+ //
+ // Add completion code in response data to meet the requirement of IPMI spec 2.0
+ //
+ *ResponseDataSize += 1; // Add one byte for Completion Code
+ for (Index = 1; Index < *ResponseDataSize; Index++) {
+ ResponseData [*ResponseDataSize - Index] = ResponseData [*ResponseDataSize - (Index + 1)];
+ }
+ ResponseData [0] = IpmiResponse->CompletionCode;
+
+ IpmiInstance->BmcStatus = BMC_OK;
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+PeiIpmiBmcStatus (
+ IN PEI_IPMI_TRANSPORT_PPI *This,
+ OUT BMC_STATUS *BmcStatus,
+ OUT SM_COM_ADDRESS *ComAddress,
+ IN VOID *Context
+ )
+/*++
+
+Routine Description:
+
+ Updates the BMC status and returns the Com Address
+
+Arguments:
+
+ This - Pointer to IPMI protocol instance
+ BmcStatus - BMC status
+ ComAddress - Com Address
+ Context - Context
+
+Returns:
+
+ EFI_SUCCESS - Success
+
+--*/
+{
+ PEI_IPMI_BMC_INSTANCE_DATA *IpmiInstance;
+
+ IpmiInstance = INSTANCE_FROM_PEI_SM_IPMI_BMC_THIS (This);
+
+ if ((IpmiInstance->BmcStatus == BMC_SOFTFAIL) && (IpmiInstance->SoftErrorCount >= MAX_SOFT_COUNT)) {
+ IpmiInstance->BmcStatus = BMC_HARDFAIL;
+ }
+
+ *BmcStatus = IpmiInstance->BmcStatus;
+ ComAddress->ChannelType = SmBmc;
+ ComAddress->Address.BmcAddress.LunAddress = 0x0;
+ ComAddress->Address.BmcAddress.SlaveAddress = IpmiInstance->SlaveAddress;
+ ComAddress->Address.BmcAddress.ChannelAddress = 0x0;
+
+ return EFI_SUCCESS;
+}
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.h
new file mode 100644
index 0000000000..40b9429e84
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.h
@@ -0,0 +1,38 @@
+/** @file
+ Generic IPMI transport layer head file during PEI phase
+
+ @copyright
+ Copyright 2016 - 2021 Intel Corporation. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PEI_IPMI_BMC_H_
+#define _PEI_IPMI_BMC_H_
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseLib.h>
+#include <Library/IoLib.h>
+#include <Library/IpmiBaseLib.h>
+
+#include <Ppi/IpmiTransportPpi.h>
+
+#include "PeiIpmiBmcDef.h"
+#include "KcsBmc.h"
+
+//
+// IPMI Instance signature
+//
+#define SM_IPMI_BMC_SIGNATURE SIGNATURE_32 ('i', 'p', 'm', 'i')
+
+#define INSTANCE_FROM_PEI_SM_IPMI_BMC_THIS(a) \
+ CR ( \
+ a, \
+ PEI_IPMI_BMC_INSTANCE_DATA, \
+ IpmiTransportPpi, \
+ SM_IPMI_BMC_SIGNATURE \
+ )
+
+#endif // _PEI_IPMI_BMC_H_
diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmcDef.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmcDef.h
new file mode 100644
index 0000000000..3fbe70ce62
--- /dev/null
+++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmcDef.h
@@ -0,0 +1,156 @@
+/** @file
+ Generic IPMI transport layer common head file during PEI phase
+
+ @copyright
+ Copyright 2016 - 2021 Intel Corporation. <BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PEI_IPMI_COMMON_BMC_H_
+#define _PEI_IPMI_COMMON_BMC_H_
+
+#include <Ppi/IpmiTransportPpi.h>
+
+#define MAX_TEMP_DATA 160
+#define BMC_SLAVE_ADDRESS 0x20
+#define MAX_SOFT_COUNT 10
+#define COMP_CODE_NORMAL 0x00
+
+//
+// IPMI command completion codes to check for in the UpdateErrorStatus routine.
+// These completion codes indicate a soft error and a running total of the occurrences
+// of these errors is maintained.
+//
+#define COMP_CODE_NODE_BUSY 0xC0
+#define COMP_CODE_TIMEOUT 0xC3
+#define COMP_CODE_OUT_OF_SPACE 0xC4
+#define COMP_CODE_OUT_OF_RANGE 0xC9
+#define COMP_CODE_CMD_RESP_NOT_PROVIDED 0xCE
+#define COMP_CODE_FAIL_DUP_REQUEST 0xCF
+#define COMP_CODE_SDR_REP_IN_UPDATE_MODE 0xD0
+#define COMP_CODE_DEV_IN_FW_UPDATE_MODE 0xD1
+#define COMP_CODE_BMC_INIT_IN_PROGRESS 0xD2
+#define COMP_CODE_UNSPECIFIED 0xFF
+
+#define COMPLETION_CODES \
+ { \
+ COMP_CODE_NODE_BUSY, COMP_CODE_TIMEOUT, COMP_CODE_OUT_OF_SPACE, COMP_CODE_OUT_OF_RANGE, \
+ COMP_CODE_CMD_RESP_NOT_PROVIDED, COMP_CODE_FAIL_DUP_REQUEST, COMP_CODE_SDR_REP_IN_UPDATE_MODE, \
+ COMP_CODE_DEV_IN_FW_UPDATE_MODE, COMP_CODE_BMC_INIT_IN_PROGRESS, COMP_CODE_UNSPECIFIED \
+ }
+//
+// Ensure proper structure formats
+//
+#pragma pack(1)
+//
+// Pei Ipmi instance data
+//
+typedef struct {
+ UINTN Signature;
+ UINT64 KcsTimeoutPeriod;
+ UINT8 SlaveAddress;
+ UINT8 TempData[MAX_TEMP_DATA];
+ BMC_STATUS BmcStatus;
+ UINT64 ErrorStatus;
+ UINT8 SoftErrorCount;
+ UINT16 IpmiIoBase;
+ PEI_IPMI_TRANSPORT_PPI IpmiTransportPpi;
+ EFI_PEI_PPI_DESCRIPTOR PeiIpmiBmcDataDesc;
+} PEI_IPMI_BMC_INSTANCE_DATA;
+
+//
+// Structure of IPMI Command buffer
+//
+#define IPMI_COMMAND_HEADER_SIZE 2
+
+typedef struct {
+ UINT8 Lun : 2;
+ UINT8 NetFunction : 6;
+ UINT8 Command;
+ UINT8 CommandData[MAX_TEMP_DATA - IPMI_COMMAND_HEADER_SIZE];
+} IPMI_COMMAND;
+
+//
+// Structure of IPMI Command response buffer
+//
+#define IPMI_RESPONSE_HEADER_SIZE 3
+
+typedef struct {
+ UINT8 Lun : 2;
+ UINT8 NetFunction : 6;
+ UINT8 Command;
+ UINT8 CompletionCode;
+ UINT8 ResponseData[MAX_TEMP_DATA - IPMI_RESPONSE_HEADER_SIZE];
+} IPMI_RESPONSE;
+#pragma pack()
+
+EFI_STATUS
+PeiIpmiSendCommandToBmc (
+ IN PEI_IPMI_TRANSPORT_PPI *This,
+ IN UINT8 NetFunction,
+ IN UINT8 Lun,
+ IN UINT8 Command,
+ IN UINT8 *CommandData,
+ IN UINT8 CommandDataSize,
+ IN OUT UINT8 *ResponseData,
+ IN OUT UINT8 *ResponseDataSize,
+ IN VOID *Context
+ )
+/*++
+
+Routine Description:
+
+ Send IPMI command to BMC
+
+Arguments:
+
+ This - Pointer to IPMI protocol instance
+ NetFunction - Net Function of command to send
+ Lun - LUN of command to send
+ Command - IPMI command to send
+ CommandData - Pointer to command data buffer, if needed
+ CommandDataSize - Size of command data buffer
+ ResponseData - Pointer to response data buffer
+ ResponseDataSize - Pointer to response data buffer size
+ Context - Context
+
+Returns:
+
+ EFI_INVALID_PARAMETER - One of the input values is bad
+ EFI_DEVICE_ERROR - IPMI command failed
+ EFI_BUFFER_TOO_SMALL - Response buffer is too small
+ EFI_SUCCESS - Command completed successfully
+
+--*/
+;
+
+
+EFI_STATUS
+PeiIpmiBmcStatus (
+ IN PEI_IPMI_TRANSPORT_PPI *This,
+ OUT BMC_STATUS *BmcStatus,
+ OUT SM_COM_ADDRESS *ComAddress,
+ IN VOID *Context
+ )
+/*++
+
+Routine Description:
+
+ Updates the BMC status and returns the Com Address
+
+Arguments:
+
+ This - Pointer to IPMI protocol instance
+ BmcStatus - BMC status
+ ComAddress - Com Address
+ Context - Context
+
+Returns:
+
+ EFI_SUCCESS - Success
+
+--*/
+;
+
+
+#endif //_PEI_IPMI_COMMON_BMC_H_
--
2.27.0.windows.1
next prev parent reply other threads:[~2021-03-02 2:29 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-03-02 2:27 [edk2-platforms] [PATCH v1 0/9] IpmiFeaturePkg: Add IPMI transport drivers Nate DeSimone
2021-03-02 2:27 ` [edk2-platforms] [PATCH v1 1/9] IpmiFeaturePkg: Add IPMI driver Include headers Nate DeSimone
2021-03-02 2:27 ` [edk2-platforms] [PATCH v1 2/9] IpmiFeaturePkg: Add IpmiBaseLib and IpmiCommandLib Nate DeSimone
2021-03-02 2:27 ` [edk2-platforms] [PATCH v1 3/9] IpmiFeaturePkg: Add IpmiInit driver DEPEXs Nate DeSimone
2021-03-02 2:27 ` [edk2-platforms] [PATCH v1 4/9] IpmiFeaturePkg: Add GenericIpmi driver common code Nate DeSimone
2021-03-02 2:28 ` Nate DeSimone [this message]
2021-03-02 2:28 ` [edk2-platforms] [PATCH v1 6/9] IpmiFeaturePkg: Add GenericIpmi DXE Driver Nate DeSimone
2021-03-02 2:28 ` [edk2-platforms] [PATCH v1 7/9] IpmiFeaturePkg: Add GenericIpmi SMM Driver Nate DeSimone
2021-03-02 2:28 ` [edk2-platforms] [PATCH v1 8/9] IpmiFeaturePkg: Add IPMI driver build files Nate DeSimone
2021-03-02 2:28 ` [edk2-platforms] [PATCH v1 9/9] Maintainers.txt: Add IpmiFeaturePkg maintainers Nate DeSimone
2021-03-03 19:22 ` [edk2-devel] [edk2-platforms] [PATCH v1 0/9] IpmiFeaturePkg: Add IPMI transport drivers Michael Kubacki
2021-03-04 23:33 ` Oram, Isaac W
2021-03-05 11:06 ` Nhi Pham
2021-03-11 19:29 ` Chaganty, Rangasai V
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210302022804.8641-6-nathaniel.l.desimone@intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox