From cf2f4db7ae1efb64c55f0e2d0f024d4e52136680 Mon Sep 17 00:00:00 2001 From: Igor Kononenko Date: Mon, 20 Feb 2023 01:33:22 +0300 Subject: [PATCH] oem: implement PCIe bifurcation mode request This implements new OEM command to report PCIe bifurcation mode to UEFI. The command returns list of IIO_BIFURCATION_DATA_ENTRY structs: typedef struct _PLATFORM_IIO_BIFURCATION_ENTRY { UINT8 Socket; UINT8 IouNumber; UINT8 Bifurcation; } IIO_BIFURCATION_DATA_ENTRY; Tested: ~# host-pcie-cfg CPU PE Mode --------------------------------- 1 1 x16 1 2 x16 1 3 x8x8 --------------------------------- ~# ipmitool raw 0x2e 0xB0 0x69 0xc2 0x00 69 c2 00 01 00 04 01 01 04 01 02 03 Ported from 2f55453aec33462124f73f337169daaaeaac5de9 Signed-off-by: Andrei Kartashev Signed-off-by: Igor Kononenko --- README.md | 1 + include/host_config_cmd.hpp | 50 ++++++++++ include/oem_cmd.hpp | 3 + meson.build | 1 + src/host_config_cmd.cpp | 189 ++++++++++++++++++++++++++++++++++++ 5 files changed, 244 insertions(+) create mode 100644 include/host_config_cmd.hpp create mode 100644 src/host_config_cmd.cpp diff --git a/README.md b/README.md index e82b1a2..600ea47 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Main extensions to vanilla OpenBMC IPMI stack are the following: - SMBIOS dump (processed by MDR parser); - Connected storage list. +- Report PCIe bifurcation mode to UEFI ## References diff --git a/include/host_config_cmd.hpp b/include/host_config_cmd.hpp new file mode 100644 index 0000000..1eedcbc --- /dev/null +++ b/include/host_config_cmd.hpp @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023, KNS Group LLC (YADRO) + +#pragma once + +#include +#include + +#include + +namespace ipmi +{ +namespace yadro +{ +namespace host_config +{ + +namespace dbus +{ +namespace pcie_cfg +{ +constexpr const char* path = "/xyz/openbmc_project/control/host0/pcie"; +namespace properties +{ +constexpr const char* bifurcation = "Bifurcation"; +} // namespace properties +} // namespace pcie_cfg +} // namespace dbus + +using namespace sdbusplus::xyz::openbmc_project::Control::server; + +using BifurcationConfiguration = + std::vector>; +using DbusPropVariant = + std::variant; + +// PCIe Bifurcation mode +static constexpr uint8_t pcieBifurcateX4X4X4X4 = 0; +static constexpr uint8_t pcieBifurcateX4X4XXX8 = 1; +static constexpr uint8_t pcieBifurcateXXX8X4X4 = 2; +static constexpr uint8_t pcieBifurcateXXX8XXX8 = 3; +static constexpr uint8_t pcieBifurcateXXXXXX16 = 4; +static constexpr uint8_t pcieBifurcateXXXXXXXX = 0xF; + +// PCIe Bifurcation modes list (Socket, IouNumber) -> Bifurcation +using DefaultConfiguration = std::map, uint8_t>; + +} // namespace host_config +} // namespace yadro +} // namespace ipmi diff --git a/include/oem_cmd.hpp b/include/oem_cmd.hpp index b25cfcc..546c182 100644 --- a/include/oem_cmd.hpp +++ b/include/oem_cmd.hpp @@ -23,6 +23,9 @@ static constexpr ipmi::Cmd cmdSmbios = 0xa0; /** @brief Command number for Storage list. */ static constexpr ipmi::Cmd cmdStorage = 0xa1; +/** @brief Command number for get PCIe Bifurcation config. */ +static constexpr ipmi::Cmd cmdGetPCIeBifurcation = 0xb0; + } // namespace cmd } // namespace yadro diff --git a/meson.build b/meson.build index 113ddb1..c078926 100644 --- a/meson.build +++ b/meson.build @@ -33,6 +33,7 @@ incdir = include_directories('src', 'include') shared_library('yadroipmioem', 'src/oem_cmd.cpp', 'src/inventory_cmd.cpp', + 'src/host_config_cmd.cpp', include_directories : incdir, implicit_include_directories: false, dependencies: [ diff --git a/src/host_config_cmd.cpp b/src/host_config_cmd.cpp new file mode 100644 index 0000000..ffed8c7 --- /dev/null +++ b/src/host_config_cmd.cpp @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023, KNS Group LLC (YADRO) + +#include + +#include +#include +#include +#include + +#include +#include + +using namespace phosphor::logging; + +namespace ipmi +{ +namespace yadro +{ +namespace host_config +{ + +/** @brief Register IPMI OEM command handler. */ +void registerHostConfigHandlers() __attribute__((constructor)); + +/** + * @brief Convert PCIe bifurcation mode to UEFI representation + */ +uint8_t convertBifurcation(const PCIe::BifurcationMode bifurcation, + const uint8_t fallback) +{ + switch (bifurcation) + { + case PCIe::BifurcationMode::x4x4x4x4: + return pcieBifurcateX4X4X4X4; + case PCIe::BifurcationMode::x4x4x8: + return pcieBifurcateX4X4XXX8; + case PCIe::BifurcationMode::x8x4x4: + return pcieBifurcateXXX8X4X4; + case PCIe::BifurcationMode::x8x8: + return pcieBifurcateXXX8XXX8; + case PCIe::BifurcationMode::x16: + return pcieBifurcateXXXXXX16; + + case PCIe::BifurcationMode::lo_x8: + { + switch (fallback) + { + case pcieBifurcateX4X4X4X4: + case pcieBifurcateX4X4XXX8: + return pcieBifurcateX4X4XXX8; + default: + return pcieBifurcateXXX8XXX8; + } + break; + } + case PCIe::BifurcationMode::lo_x4x4: + { + switch (fallback) + { + case pcieBifurcateX4X4X4X4: + case pcieBifurcateX4X4XXX8: + return pcieBifurcateX4X4X4X4; + default: + return pcieBifurcateXXX8X4X4; + } + break; + } + case PCIe::BifurcationMode::hi_x8: + { + switch (fallback) + { + case pcieBifurcateX4X4X4X4: + case pcieBifurcateXXX8X4X4: + return pcieBifurcateXXX8X4X4; + default: + return pcieBifurcateXXX8XXX8; + } + break; + } + case PCIe::BifurcationMode::hi_x4x4: + { + switch (fallback) + { + case pcieBifurcateX4X4X4X4: + case pcieBifurcateXXX8X4X4: + return pcieBifurcateX4X4X4X4; + default: + return pcieBifurcateX4X4XXX8; + } + break; + } + + case PCIe::BifurcationMode::disabled: + return pcieBifurcateXXXXXXXX; + } + + log( + "Don't know how to deal with requested bifurcation mode, using " + "fallback", + entry("VALUE=%s", + PCIe::convertBifurcationModeToString(bifurcation).c_str()), + entry("DEFAULT=%d", fallback)); + return fallback; +} + +/** + * @brief Handler of IPMI OEM messages for request PCIe bifurcation + * configuration. + */ +static ipmi::RspType> + ipmiOEMGetPCIeBifurcation(ipmi::Context::ptr ctx, + std::vector inputData) +{ + std::vector result; + if (inputData.size() % 3) + { + return ipmi::responseReqDataLenInvalid(); + } + + DefaultConfiguration defaultCfg; + uint8_t* buf; + int len; + for (buf = inputData.data(), len = inputData.size(); len > 0; + buf += 3, len -= 3) + { + const uint8_t socket = buf[0]; + const uint8_t iouNum = buf[1]; + const uint8_t bif = buf[2]; + defaultCfg.emplace(std::make_pair(socket, iouNum), bif); + } + + std::string service; + boost::system::error_code ec = + ipmi::getService(ctx, PCIe::interface, dbus::pcie_cfg::path, service); + if (ec) + { + log("Failed to get service", + entry("ERROR=%s", ec.message().c_str()), + entry("PATH=%s", dbus::pcie_cfg::path), + entry("INTERFACE=%s", PCIe::interface)); + ipmi::responseUnspecifiedError(); + } + + BifurcationConfiguration bifurcationConfig; + ec = ipmi::getDbusProperty( + ctx, service, dbus::pcie_cfg::path, PCIe::interface, + dbus::pcie_cfg::properties::bifurcation, bifurcationConfig); + if (ec) + { + log("Failed to get propriety", + entry("ERROR=%s", ec.message().c_str()), + entry("PATH=%s", dbus::pcie_cfg::path), + entry("INTERFACE=%s", PCIe::interface)); + ipmi::responseUnspecifiedError(); + } + for (auto [socket, iouNumber, bifurcation] : bifurcationConfig) + { + iouNumber -= 1; // iouNumber is 0-based in BIOS, but 1-based in BMC + // this is for historical reasons and now can't be + // changed without break Manufacturing/QC. + auto found = defaultCfg.find({socket, iouNumber}); + if (found == defaultCfg.end()) + { + log("Unexpected Socket or PCIe port number", + entry("SOCKET=%d", socket), + entry("PORT=%d", iouNumber)); + continue; + } + uint8_t fallback = found->second; + auto bifurcationCode = convertBifurcation(bifurcation, fallback); + result.emplace_back(socket); + result.emplace_back(iouNumber); + result.emplace_back(bifurcationCode); + } + return ipmi::responseSuccess(result); +} + +void registerHostConfigHandlers() +{ + log("Registering OEM handler for Host Configuration"); + ipmi::registerOemHandler(ipmi::prioOpenBmcBase, ianaYadro, + cmd::cmdGetPCIeBifurcation, ipmi::Privilege::Admin, + ipmiOEMGetPCIeBifurcation); +} + +} // namespace host_config +} // namespace yadro +} // namespace ipmi