| /** @file | |
| SSIF instance of Manageability Transport Library | |
| Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Uefi.h> | |
| #include <IndustryStandard/IpmiSsif.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/ManageabilityTransportHelperLib.h> | |
| #include <Library/ManageabilityTransportIpmiLib.h> | |
| #include <Library/ManageabilityTransportLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/PlatformBmcReadyLib.h> | |
| #include "ManageabilityTransportSsif.h" | |
| MANAGEABILITY_TRANSPORT_SSIF *mSingleSessionToken = NULL; | |
| EFI_GUID *mSupportedManageabilityProtocol[] = { | |
| &gManageabilityProtocolIpmiGuid | |
| }; | |
| UINT8 mNumberOfSupportedProtocol = (sizeof (mSupportedManageabilityProtocol) / sizeof (EFI_GUID *)); | |
| MANAGEABILITY_TRANSPORT_SSIF_HARDWARE_INFO mSsifHardwareInfo; | |
| // | |
| // Initialize SSIF Interface capabilities | |
| // | |
| BOOLEAN mPecSupport = FALSE; | |
| UINT8 mMaxRequestSize = IPMI_SSIF_MAXIMUM_PACKET_SIZE_IN_BYTES; | |
| UINT8 mMaxResponseSize = IPMI_SSIF_MAXIMUM_PACKET_SIZE_IN_BYTES; | |
| UINT8 mTransactionSupport = IPMI_GET_SYSTEM_INTERFACE_CAPABILITIES_SSIF_TRANSACTION_SUPPORT_SINGLE_PARTITION_RW; | |
| /** | |
| This function initializes the transport interface. | |
| @param [in] TransportToken The transport token acquired through | |
| AcquireTransportSession function. | |
| @param [in] HardwareInfo The hardware information | |
| assigned to SSIF transport interface. | |
| @retval EFI_SUCCESS Transport interface is initialized | |
| successfully. | |
| @retval EFI_INVALID_PARAMETER The invalid transport token. | |
| @retval EFI_NOT_READY The transport interface works fine but | |
| @retval is not ready. | |
| @retval EFI_DEVICE_ERROR The transport interface has problems. | |
| @retval EFI_ALREADY_STARTED Teh protocol interface has already initialized. | |
| @retval Otherwise Other errors. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SsifTransportInit ( | |
| IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, | |
| IN MANAGEABILITY_TRANSPORT_HARDWARE_INFORMATION HardwareInfo OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| CHAR16 *ManageabilityProtocolName; | |
| if (TransportToken == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: Invalid transport token.\n", __func__)); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (HardwareInfo.Ssif == NULL) { | |
| DEBUG ((DEBUG_MANAGEABILITY_INFO, "%a: Hardware information is not provided, use default settings.\n", __func__)); | |
| mSsifHardwareInfo.BmcSlaveAddress = FixedPcdGet8 (PcdIpmiSsifSmbusSlaveAddr); | |
| } else { | |
| mSsifHardwareInfo.BmcSlaveAddress = ((MANAGEABILITY_TRANSPORT_SSIF_HARDWARE_INFO *)HardwareInfo.Ssif)->BmcSlaveAddress; | |
| } | |
| Status = SsifTransportGetCapabilities ( | |
| &mPecSupport, | |
| &mTransactionSupport, | |
| &mMaxRequestSize, | |
| &mMaxResponseSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_MANAGEABILITY_INFO, "%a: Could not retrieve IPMI SSIF capabilites, use default settings.\n", __func__)); | |
| } | |
| // Get protocol specification name. | |
| ManageabilityProtocolName = HelperManageabilitySpecName (TransportToken->ManageabilityProtocolSpecification); | |
| DEBUG ((DEBUG_MANAGEABILITY_INFO, "%a: transport hardware for %s is:\n", __func__, ManageabilityProtocolName)); | |
| DEBUG ((DEBUG_MANAGEABILITY_INFO, "BMC Slave Address: 0x%x\n", mSsifHardwareInfo.BmcSlaveAddress)); | |
| DEBUG ((DEBUG_MANAGEABILITY_INFO, "PEC Support: %d\n", mPecSupport)); | |
| DEBUG ((DEBUG_MANAGEABILITY_INFO, "Transaction Support: %d\n", mTransactionSupport)); | |
| DEBUG ((DEBUG_MANAGEABILITY_INFO, "Max Request Size: %d\n", mMaxRequestSize)); | |
| DEBUG ((DEBUG_MANAGEABILITY_INFO, "Max Response Size: %d\n", mMaxResponseSize)); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function returns the transport interface status. | |
| The generic EFI_STATUS is returned to caller directly, The additional | |
| information of transport interface could be optionally returned in | |
| TransportAdditionalStatus to describes the status that can't be | |
| described obviously through EFI_STATUS. | |
| See the definition of MANAGEABILITY_TRANSPORT_STATUS. | |
| @param [in] TransportToken The transport token acquired through | |
| AcquireTransportSession function. | |
| @param [out] TransportAdditionalStatus The additional status of transport | |
| interface. | |
| NULL means no additional status of this | |
| transport interface. | |
| @retval EFI_SUCCESS Transport interface status is returned. | |
| @retval EFI_INVALID_PARAMETER The invalid transport token. | |
| @retval EFI_DEVICE_ERROR The transport interface has problems to return | |
| @retval EFI_UNSUPPORTED The transport interface doesn't have status report. | |
| Otherwise Other errors. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SsifTransportStatus ( | |
| IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, | |
| OUT MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS *TransportAdditionalStatus OPTIONAL | |
| ) | |
| { | |
| if (TransportToken == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: Invalid transport token.\n", __func__)); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // SMBUS does not provide transport status checking capabilities. This only determines | |
| // if the BMC is ready or not, without updating any additional status. | |
| // | |
| if (!PlatformBmcReady ()) { | |
| return EFI_NOT_READY; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function resets the transport interface. | |
| The generic EFI_STATUS is returned to caller directly after reseting transport | |
| interface. The additional information of transport interface could be optionally | |
| returned in TransportAdditionalStatus to describes the status that can't be | |
| described obviously through EFI_STATUS. | |
| See the definition of MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS. | |
| @param [in] TransportToken The transport token acquired through | |
| AcquireTransportSession function. | |
| @param [out] TransportAdditionalStatus The additional status of specific transport | |
| interface after the reset. | |
| NULL means no additional status of this | |
| transport interface. | |
| @retval EFI_SUCCESS Transport interface status is returned. | |
| @retval EFI_INVALID_PARAMETER The invalid transport token. | |
| @retval EFI_TIMEOUT The reset process is time out. | |
| @retval EFI_DEVICE_ERROR The transport interface has problems to return | |
| status. | |
| Otherwise Other errors. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SsifTransportReset ( | |
| IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, | |
| OUT MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS *TransportAdditionalStatus OPTIONAL | |
| ) | |
| { | |
| return EFI_UNSUPPORTED; | |
| } | |
| /** | |
| This function transmit the request over target transport interface. | |
| The generic EFI_STATUS is returned to caller directly after reseting transport | |
| interface. The additional information of transport interface could be optionally | |
| returned in TransportAdditionalStatus to describes the status that can't be | |
| described obviously through EFI_STATUS. | |
| See the definition of MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS. | |
| @param [in] TransportToken The transport token acquired through | |
| AcquireTransportSession function. | |
| @param [in] TransferToken The transfer token, see the definition of | |
| MANAGEABILITY_TRANSFER_TOKEN. | |
| **/ | |
| VOID | |
| EFIAPI | |
| SsifTransportTransmitReceive ( | |
| IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, | |
| IN MANAGEABILITY_TRANSFER_TOKEN *TransferToken | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS AdditionalStatus; | |
| if ((TransportToken == NULL) || (TransferToken == NULL)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Invalid transport token or transfer token.\n", __func__)); | |
| return; | |
| } | |
| Status = SsifTransportSendCommand ( | |
| TransferToken->TransmitHeader, | |
| TransferToken->TransmitHeaderSize, | |
| TransferToken->TransmitTrailer, | |
| TransferToken->TransmitTrailerSize, | |
| TransferToken->TransmitPackage.TransmitPayload, | |
| TransferToken->TransmitPackage.TransmitSizeInByte, | |
| TransferToken->ReceivePackage.ReceiveBuffer, | |
| &TransferToken->ReceivePackage.ReceiveSizeInByte, | |
| &AdditionalStatus | |
| ); | |
| TransferToken->TransferStatus = Status; | |
| TransferToken->TransportAdditionalStatus = AdditionalStatus; | |
| } | |
| /** | |
| This function acquires to create a transport session to transmit manageability | |
| packet. A transport token is returned to caller for the follow up operations. | |
| @param [in] ManageabilityProtocolSpec The protocol spec the transport interface is acquired. | |
| @param [out] TransportToken The pointer to receive the transport token created by | |
| the target transport interface library. | |
| @retval EFI_SUCCESS Token is created successfully. | |
| @retval EFI_OUT_OF_RESOURCES Out of resource to create a new transport session. | |
| @retval EFI_UNSUPPORTED Protocol is not supported on this transport interface. | |
| @retval Otherwise Other errors. | |
| **/ | |
| EFI_STATUS | |
| AcquireTransportSession ( | |
| IN EFI_GUID *ManageabilityProtocolSpec, | |
| OUT MANAGEABILITY_TRANSPORT_TOKEN **TransportToken | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| MANAGEABILITY_TRANSPORT_SSIF *SsifTransportToken; | |
| if (ManageabilityProtocolSpec == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: No Manageability protocol specification specified.\n", __func__)); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (TransportToken == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: TransportToken is NULL.\n", __func__)); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = HelperManageabilityCheckSupportedSpec ( | |
| &gManageabilityTransportSmbusI2cGuid, | |
| mSupportedManageabilityProtocol, | |
| mNumberOfSupportedProtocol, | |
| ManageabilityProtocolSpec | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Protocol is not supported on this transport interface.\n", __func__)); | |
| return EFI_UNSUPPORTED; | |
| } | |
| if (mSingleSessionToken != NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: This manageability transport library only supports one session transport token.\n", __func__)); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| SsifTransportToken = AllocateZeroPool (sizeof (MANAGEABILITY_TRANSPORT_SSIF)); | |
| if (SsifTransportToken == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for MANAGEABILITY_TRANSPORT_SSIF\n", __func__)); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| SsifTransportToken->Token.Transport = AllocateZeroPool (sizeof (MANAGEABILITY_TRANSPORT)); | |
| if (SsifTransportToken->Token.Transport == NULL) { | |
| FreePool (SsifTransportToken); | |
| DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for MANAGEABILITY_TRANSPORT\n", __func__)); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| SsifTransportToken->Signature = MANAGEABILITY_TRANSPORT_SSIF_SIGNATURE; | |
| SsifTransportToken->Token.ManageabilityProtocolSpecification = ManageabilityProtocolSpec; | |
| SsifTransportToken->Token.Transport->TransportVersion = MANAGEABILITY_TRANSPORT_TOKEN_VERSION; | |
| SsifTransportToken->Token.Transport->ManageabilityTransportSpecification = &gManageabilityTransportSmbusI2cGuid; | |
| SsifTransportToken->Token.Transport->TransportName = L"SSIF"; | |
| SsifTransportToken->Token.Transport->Function.Version1_0 = AllocateZeroPool (sizeof (MANAGEABILITY_TRANSPORT_FUNCTION_V1_0)); | |
| if (SsifTransportToken->Token.Transport->Function.Version1_0 == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for MANAGEABILITY_TRANSPORT_FUNCTION_V1_0\n", __func__)); | |
| FreePool (SsifTransportToken->Token.Transport); | |
| FreePool (SsifTransportToken); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| SsifTransportToken->Token.Transport->Function.Version1_0->TransportInit = SsifTransportInit; | |
| SsifTransportToken->Token.Transport->Function.Version1_0->TransportReset = SsifTransportReset; | |
| SsifTransportToken->Token.Transport->Function.Version1_0->TransportStatus = SsifTransportStatus; | |
| SsifTransportToken->Token.Transport->Function.Version1_0->TransportTransmitReceive = SsifTransportTransmitReceive; | |
| mSingleSessionToken = SsifTransportToken; | |
| *TransportToken = &SsifTransportToken->Token; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function returns the transport capabilities according to | |
| the manageability protocol. | |
| @param [in] TransportToken Transport token acquired from manageability | |
| transport library. | |
| @param [out] TransportCapability Pointer to receive transport capabilities. | |
| See the definitions of | |
| MANAGEABILITY_TRANSPORT_CAPABILITY. | |
| @retval EFI_SUCCESS TransportCapability is returned successfully. | |
| @retval EFI_INVALID_PARAMETER TransportToken is not a valid token. | |
| **/ | |
| EFI_STATUS | |
| GetTransportCapability ( | |
| IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, | |
| OUT MANAGEABILITY_TRANSPORT_CAPABILITY *TransportCapability | |
| ) | |
| { | |
| if ((TransportToken == NULL) || (TransportCapability == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| *TransportCapability = 0; | |
| if (CompareGuid ( | |
| TransportToken->ManageabilityProtocolSpecification, | |
| &gManageabilityProtocolIpmiGuid | |
| )) | |
| { | |
| *TransportCapability |= | |
| (MANAGEABILITY_TRANSPORT_CAPABILITY_MAXIMUM_PAYLOAD_NOT_AVAILABLE << MANAGEABILITY_TRANSPORT_CAPABILITY_MAXIMUM_PAYLOAD_BIT_POSITION); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function releases the manageability session. | |
| @param [in] TransportToken The transport token acquired through | |
| AcquireTransportSession. | |
| @retval EFI_SUCCESS Token is released successfully. | |
| @retval EFI_INVALID_PARAMETER Invalid TransportToken. | |
| @retval Otherwise Other errors. | |
| **/ | |
| EFI_STATUS | |
| ReleaseTransportSession ( | |
| IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| MANAGEABILITY_TRANSPORT_SSIF *SsifTransportToken; | |
| Status = EFI_INVALID_PARAMETER; | |
| if (TransportToken != NULL) { | |
| SsifTransportToken = MANAGEABILITY_TRANSPORT_SSIF_FROM_LINK (TransportToken); | |
| if (SsifTransportToken != NULL) { | |
| if ((mSingleSessionToken != NULL) && | |
| (mSingleSessionToken == SsifTransportToken)) | |
| { | |
| mSingleSessionToken = NULL; | |
| Status = EFI_SUCCESS; | |
| } | |
| FreePool (SsifTransportToken->Token.Transport->Function.Version1_0); | |
| FreePool (SsifTransportToken->Token.Transport); | |
| FreePool (SsifTransportToken); | |
| } | |
| } | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Fail to release SSIF transport token (%r).\n", __func__, Status)); | |
| } | |
| return Status; | |
| } |