blob: 70c29837e7ddb546615cf07b7dbc55537cae99d9 [file]
/*
* 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