| /* |
| * SPDX-FileCopyrightText: Copyright OpenBMC Authors |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include "OcpMctpVdm.hpp" |
| |
| #include "MessagePackUnpackUtils.hpp" |
| |
| #include <endian.h> |
| |
| #include <cerrno> |
| #include <cstdint> |
| #include <functional> |
| #include <span> |
| |
| namespace ocp |
| { |
| namespace accelerator_management |
| { |
| |
| int packHeader(PackBuffer& buffer, uint16_t pciVendorId, |
| MessageType ocpAcceleratorManagementMsgType, uint8_t instanceId, |
| uint8_t msgType) |
| { |
| if (ocpAcceleratorManagementMsgType != MessageType::RESPONSE && |
| ocpAcceleratorManagementMsgType != MessageType::REQUEST) |
| { |
| return EINVAL; |
| } |
| |
| if (instanceId > instanceMax) |
| { |
| return EINVAL; |
| } |
| |
| uint8_t messageInstanceId = instanceId & instanceIdBitMask; |
| |
| if (ocpAcceleratorManagementMsgType == MessageType::REQUEST) |
| { |
| messageInstanceId |= requestBitMask; |
| } |
| else |
| { |
| messageInstanceId &= ~requestBitMask; |
| } |
| |
| messageInstanceId &= ~instanceIdReservedBitMask; |
| |
| uint8_t ocpVersionAndType = ocpVersion & ocpVersionBitMask; |
| ocpVersionAndType |= (ocpType << ocpTypeBitOffset) & ocpTypeBitMask; |
| |
| buffer.pack(htobe16(pciVendorId)); |
| buffer.pack(messageInstanceId); |
| buffer.pack(ocpVersionAndType); |
| buffer.pack(msgType); |
| |
| return 0; |
| } |
| |
| int unpackHeader(UnpackBuffer& buffer, uint16_t pciVendorId, |
| MessageType& ocpAcceleratorManagementMsgType, |
| uint8_t& instanceId, uint8_t& msgType) |
| { |
| uint16_t receivedPciVendorId = 0; |
| uint8_t messageInstanceId = 0; |
| uint8_t ocpVersionAndType = 0; |
| |
| buffer.unpack(receivedPciVendorId); |
| buffer.unpack(messageInstanceId); |
| buffer.unpack(ocpVersionAndType); |
| buffer.unpack(msgType); |
| |
| if (buffer.getError() != 0) |
| { |
| return buffer.getError(); |
| } |
| |
| if (receivedPciVendorId != htobe16(pciVendorId)) |
| { |
| return EINVAL; |
| } |
| |
| instanceId = messageInstanceId & instanceIdBitMask; |
| |
| if ((messageInstanceId & requestBitMask) != 0) |
| { |
| ocpAcceleratorManagementMsgType = MessageType::REQUEST; |
| } |
| else |
| { |
| ocpAcceleratorManagementMsgType = MessageType::RESPONSE; |
| } |
| |
| if ((messageInstanceId & instanceIdReservedBitMask) != 0) |
| { |
| return EINVAL; |
| } |
| |
| if ((ocpVersionAndType & ocpVersionBitMask) != ocpVersion) |
| { |
| return EINVAL; |
| } |
| |
| if ((ocpVersionAndType & ocpTypeBitMask) != (ocpType << ocpTypeBitOffset)) |
| { |
| return EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| int unpackReasonCodeAndCC(UnpackBuffer& buffer, CompletionCode& cc, |
| uint16_t& reasonCode) |
| { |
| uint8_t completionCode = 0; |
| uint16_t receivedReasonCode = 0; |
| |
| buffer.unpack(completionCode); |
| buffer.unpack(receivedReasonCode); |
| |
| if (buffer.getError() != 0) |
| { |
| return buffer.getError(); |
| } |
| |
| cc = static_cast<CompletionCode>(completionCode); |
| |
| if (cc == CompletionCode::SUCCESS) |
| { |
| reasonCode = 0; |
| } |
| else |
| { |
| reasonCode = receivedReasonCode; |
| } |
| |
| return 0; |
| } |
| |
| int unpackAggregateResponse( |
| UnpackBuffer& buffer, |
| std::move_only_function<int(const uint8_t tag, const uint8_t length, |
| UnpackBuffer& buffer)> |
| handler) |
| { |
| uint16_t totalTelemetryCount = 0; |
| int rc = buffer.unpack(totalTelemetryCount); |
| |
| if (rc != 0) |
| { |
| return rc; |
| } |
| |
| for (uint16_t telemetryCount = 0; telemetryCount < totalTelemetryCount; |
| ++telemetryCount) |
| { |
| uint8_t tag = 0; |
| rc = buffer.unpack(tag); |
| |
| if (rc != 0) |
| { |
| return rc; |
| } |
| |
| uint8_t tagInfo = 0; |
| rc = buffer.unpack(tagInfo); |
| |
| if (rc != 0) |
| { |
| return rc; |
| } |
| |
| const bool isValid = (0x01 & tagInfo) != 0; |
| const bool isByteLengthEncoding = (0x80 & tagInfo) != 0; |
| const uint8_t encodedLength = (tagInfo >> 1) & 0x07; |
| |
| uint8_t length = 0; |
| if (isByteLengthEncoding) |
| { |
| length = encodedLength; |
| } |
| else |
| { |
| length = 1 << encodedLength; |
| } |
| |
| if (isValid) |
| { |
| rc = handler(tag, length, buffer); |
| |
| if (rc != 0) |
| { |
| return rc; |
| } |
| } |
| else |
| { |
| buffer.skip(length); |
| } |
| } |
| |
| return 0; |
| } |
| |
| int decodeInstanceId(std::span<const uint8_t> buf, uint8_t& instanceId) |
| { |
| if (buf.size() < ocp::accelerator_management::messageHeaderSize) |
| { |
| return EINVAL; |
| } |
| |
| instanceId = buf[ocp::accelerator_management::instanceIdOffset] & |
| ocp::accelerator_management::instanceIdBitMask; |
| |
| return 0; |
| } |
| |
| int decodeEvent(std::span<const uint8_t> buf, uint16_t pciVendorId, |
| uint8_t& messageType, bool& ackRequired, uint8_t& version, |
| uint8_t& eventId, uint8_t& eventClass, uint16_t& eventState, |
| uint8_t& size, std::span<const uint8_t>& eventData) |
| { |
| UnpackBuffer buffer(buf); |
| |
| uint16_t receivedPciVendorId = 0; |
| uint8_t instanceId = 0; |
| uint8_t ocpVersion = 0; |
| uint8_t versionByte = 0; |
| |
| buffer.unpack(receivedPciVendorId); |
| buffer.unpack(instanceId); |
| buffer.unpack(ocpVersion); |
| buffer.unpack(messageType); |
| buffer.unpack(versionByte); |
| buffer.unpack(eventId); |
| buffer.unpack(eventClass); |
| buffer.unpack(eventState); |
| buffer.unpack(size); |
| |
| if (buffer.getError() != 0) |
| { |
| return buffer.getError(); |
| } |
| |
| if (receivedPciVendorId != htobe16(pciVendorId)) |
| { |
| return EINVAL; |
| } |
| |
| ackRequired = ((versionByte & eventAckRequiredBitMask) != 0); |
| version = versionByte & eventVersionBitMask; |
| |
| if (buf.size() < eventHeaderSize + size) |
| { |
| return EINVAL; |
| } |
| |
| eventData = buf.subspan(eventHeaderSize, size); |
| |
| return 0; |
| } |
| |
| } // namespace accelerator_management |
| } // namespace ocp |