Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions redfish-core/include/amd_host_inventory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright OpenBMC Authors
#pragma once

// AMD HPAR (2x1P) helper.
//
// bmcweb exchanges CBS/PCIe/DIMM/Storage data with BIOS through the
// iodevices-inventory "PcieData" D-Bus interface. In 2x1P that service runs as
// one instance per host, so the target service name and object path depend on
// which host the request is for. The host is selected by the "?HostNumber=N"
// query parameter (the same idiom already used for RAS, power-cap and
// clear-CMOS).
//
// HostNumber 0 or absent keeps the legacy single-host (2P / host0) service name
// and object path, so existing 2P behaviour is completely unchanged. Hosts 1
// and 2 map to the two independent iodevices-inventory instances in 2x1P and
// mirror iodevices-inventory's hostServiceName()/hostInventoryPath():
// host0 : xyz.openbmc_project.PCIe /xyz/openbmc_project/inventory/PCIe
// hostN : xyz.openbmc_project.PCIe.hostN /xyz/openbmc_project/inventory/hostN/PCIe

#include "http_request.hpp"

#include <boost/url/url_view.hpp>

#include <cstdint>
#include <filesystem>
#include <string>

namespace redfish::amd_hpar
{

// True when the BMC is running in single-host / 2P mode (host0 partition).
// multi-host-config writes host0.conf for 2P and host1.conf/host2.conf for
// 2x1P, and the iodevices-inventory / power-control / usb-network instances are
// all gated on the same files, so this is the authoritative mode selector.
inline bool is2pMode()
{
std::error_code ec;
return std::filesystem::exists("/etc/amd/hosts.d/host0.conf", ec);
}

// Map the USB vNIC a request arrived on to a host instance. BIOS pushes
// CBS/PCIe/DIMM/Storage data through the Redfish host interface over a per-host
// vNIC and cannot set the "?HostNumber" query parameter, so the host has to be
// inferred from the source address. This mirrors amd-ipmi-oem
// resolveHostInterface():
// usb0 192.168.31.x -> P0 -> host0 in 2P, host1 in 2x1P
// usb1 192.168.32.x -> P1 -> host2
// Returns 0 for any other interface (eth0, loopback, ...) so normal Redfish
// clients are unaffected.
inline uint8_t hostNumberFromVnic(const crow::Request& req)
{
const std::string ip = req.ipAddress.to_string();
if (ip.find("192.168.31.") != std::string::npos)
{
return is2pMode() ? 0 : 1;
}
if (ip.find("192.168.32.") != std::string::npos)
{
return 2;
}
return 0;
}

// Resolve the target host for a request.
// 1. An explicit "?HostNumber=N" (1..2) always wins - lets a normal Redfish
// client target a specific host in 2x1P.
// 2. Otherwise fall back to the source vNIC so BIOS pushes (which have no
// HostNumber) reach the right per-host iodevices-inventory instance in
// 2x1P without any BIOS-side change.
// Absent/invalid/out-of-range and non-vNIC sources => 0 (single-host / 2P), so
// existing 2P behaviour is completely unchanged.
inline uint8_t hostNumberFromReq(const crow::Request& req)
{
boost::urls::url_view urlView = req.url();
for (const auto& param : urlView.params())
{
if (param.key == "HostNumber" && !param.value.empty())
{
try
{
int temp = std::stoi(std::string(param.value));
if (temp > 0 && temp <= 2)
{
return static_cast<uint8_t>(temp);
}
}
catch (const std::exception&)
{
return 0;
}
return 0;
}
}
return hostNumberFromVnic(req);
}

// iodevices-inventory well-known service name for the given host.
inline std::string pcieDataService(uint8_t hostNumber)
{
if (hostNumber == 0)
{
return "xyz.openbmc_project.PCIe";
}
return "xyz.openbmc_project.PCIe.host" + std::to_string(hostNumber);
}

// Object that hosts the PcieData interface for the given host.
inline std::string pcieDataObject(uint8_t hostNumber)
{
if (hostNumber == 0)
{
return "/xyz/openbmc_project/inventory/PCIe";
}
return "/xyz/openbmc_project/inventory/host" + std::to_string(hostNumber) +
"/PCIe";
}

} // namespace redfish::amd_hpar
62 changes: 42 additions & 20 deletions redfish-core/lib/bios.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "bmcweb_config.h"

#include "amd_host_inventory.hpp"
#include "app.hpp"
#include "async_resp.hpp"
#include "dbus_utility.hpp"
Expand Down Expand Up @@ -252,6 +253,9 @@ inline void handleBiosServiceGet(

asyncResp->res.jsonValue["Attributes"] = nlohmann::json::object();

uint8_t hostNumber = redfish::amd_hpar::hostNumberFromReq(req);
std::string pcieSvc = redfish::amd_hpar::pcieDataService(hostNumber);
std::string pcieObj = redfish::amd_hpar::pcieDataObject(hostNumber);
crow::connections::systemBus->async_method_call(
[asyncResp](const boost::system::error_code ec, BiosAttrMap& newtable) {
if (ec)
Expand All @@ -276,18 +280,21 @@ inline void handleBiosServiceGet(
messages::success(asyncResp->res);
return;
},
"xyz.openbmc_project.PCIe", "/xyz/openbmc_project/inventory/PCIe",
pcieSvc, pcieObj,
"xyz.openbmc_project.PCIe.PcieData", "GetBiosAttribute");
}

inline void setPendingAttributes(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const BiosAttrMap& patchMap)
const BiosAttrMap& patchMap, uint8_t hostNumber)
{
std::string pcieSvc = redfish::amd_hpar::pcieDataService(hostNumber);
std::string pcieObj = redfish::amd_hpar::pcieDataObject(hostNumber);
// now do the get the persistent value
crow::connections::systemBus->async_method_call(
[asyncResp, patchMap](const boost::system::error_code ec,
BiosAttrMap& PendingAttrData) {
[asyncResp, patchMap, pcieSvc, pcieObj](
const boost::system::error_code ec,
BiosAttrMap& PendingAttrData) {
if (ec)
{
BMCWEB_LOG_ERROR(
Expand Down Expand Up @@ -319,12 +326,11 @@ inline void setPendingAttributes(
messages::success(asyncResp->res);
return;
},
"xyz.openbmc_project.PCIe",
"/xyz/openbmc_project/inventory/PCIe",
pcieSvc, pcieObj,
"xyz.openbmc_project.PCIe.PcieData", "SetPendingAttribute",
PendingAttrData);
},
"xyz.openbmc_project.PCIe", "/xyz/openbmc_project/inventory/PCIe",
pcieSvc, pcieObj,
"xyz.openbmc_project.PCIe.PcieData", "GetPendingAttribute");
}

Expand All @@ -334,8 +340,10 @@ inline void setPendingAttributes(
**/
inline void setBiosAttributes(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const BiosAttrMap& table)
const BiosAttrMap& table, uint8_t hostNumber)
{
std::string pcieSvc = redfish::amd_hpar::pcieDataService(hostNumber);
std::string pcieObj = redfish::amd_hpar::pcieDataObject(hostNumber);
// make dbus call transfer the data
crow::connections::systemBus->async_method_call(
[asyncResp](const boost::system::error_code ec) {
Expand All @@ -350,14 +358,16 @@ inline void setBiosAttributes(
asyncResp->res.jsonValue["status"] = "ok";
return;
},
"xyz.openbmc_project.PCIe", "/xyz/openbmc_project/inventory/PCIe",
pcieSvc, pcieObj,
"xyz.openbmc_project.PCIe.PcieData", "SetBiosAttribute", table);
}

inline void setBiosRegistryAttributes(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const BiosRegistryAttrMap& table)
const BiosRegistryAttrMap& table, uint8_t hostNumber)
{
std::string pcieSvc = redfish::amd_hpar::pcieDataService(hostNumber);
std::string pcieObj = redfish::amd_hpar::pcieDataObject(hostNumber);
crow::connections::systemBus->async_method_call(
[asyncResp](const boost::system::error_code ec) {
if (ec)
Expand All @@ -370,7 +380,7 @@ inline void setBiosRegistryAttributes(
messages::success(asyncResp->res);
asyncResp->res.jsonValue["status"] = "ok";
},
"xyz.openbmc_project.PCIe", "/xyz/openbmc_project/inventory/PCIe",
pcieSvc, pcieObj,
"xyz.openbmc_project.PCIe.PcieData", "SetBiosRegistryAttribute",
table);
}
Expand Down Expand Up @@ -415,9 +425,12 @@ inline void handleBiosServicePatch(
}

// now do the get the persistent value
uint8_t hostNumber = redfish::amd_hpar::hostNumberFromReq(req);
std::string pcieSvc = redfish::amd_hpar::pcieDataService(hostNumber);
std::string pcieObj = redfish::amd_hpar::pcieDataObject(hostNumber);
crow::connections::systemBus->async_method_call(
[asyncResp,
patchMap](const boost::system::error_code ec, BiosAttrMap& allData) {
[asyncResp, patchMap, hostNumber](const boost::system::error_code ec,
BiosAttrMap& allData) {
if (ec)
{
BMCWEB_LOG_DEBUG(
Expand Down Expand Up @@ -450,7 +463,7 @@ inline void handleBiosServicePatch(
if (status)
{
// setBiosAttributes(asyncResp, allData);
setPendingAttributes(asyncResp, patchMap);
setPendingAttributes(asyncResp, patchMap, hostNumber);
messages::success(asyncResp->res);
asyncResp->res.jsonValue["status"] = "ok";
}
Expand All @@ -460,7 +473,7 @@ inline void handleBiosServicePatch(
asyncResp->res.jsonValue["status"] = "error";
}
},
"xyz.openbmc_project.PCIe", "/xyz/openbmc_project/inventory/PCIe",
pcieSvc, pcieObj,
"xyz.openbmc_project.PCIe.PcieData", "GetBiosAttribute");
}

Expand Down Expand Up @@ -504,7 +517,8 @@ inline void handleBiosServicePost(
// call function with Param in
BiosAttrMap table = JsonToBiosAttributes(biosPostJsonObject["Attributes"]);
// make dbus call transfer the data
setBiosAttributes(asyncResp, table);
uint8_t hostNumber = redfish::amd_hpar::hostNumberFromReq(req);
setBiosAttributes(asyncResp, table, hostNumber);
}

/**
Expand Down Expand Up @@ -547,7 +561,8 @@ inline void handleBiosServicePut(
// call function with Param in
BiosAttrMap table = JsonToBiosAttributes(biosPostJsonObject["Attributes"]);
// make dbus call transfer the data
setBiosAttributes(asyncResp, table);
uint8_t hostNumber = redfish::amd_hpar::hostNumberFromReq(req);
setBiosAttributes(asyncResp, table, hostNumber);
}

inline void requestRoutesBiosService(App& app)
Expand Down Expand Up @@ -698,6 +713,9 @@ inline void handleBiosSettingsGet(
asyncResp->res.jsonValue["Id"] = "BIOS";
asyncResp->res.jsonValue["Name"] = "BIOS Configuration";
asyncResp->res.jsonValue["Attributes"] = nlohmann::json::object();
uint8_t hostNumber = redfish::amd_hpar::hostNumberFromReq(req);
std::string pcieSvc = redfish::amd_hpar::pcieDataService(hostNumber);
std::string pcieObj = redfish::amd_hpar::pcieDataObject(hostNumber);
// now do the get the persistent value
crow::connections::systemBus->async_method_call(
[asyncResp](const boost::system::error_code ec,
Expand Down Expand Up @@ -725,7 +743,7 @@ inline void handleBiosSettingsGet(
messages::success(asyncResp->res);
return;
},
"xyz.openbmc_project.PCIe", "/xyz/openbmc_project/inventory/PCIe",
pcieSvc, pcieObj,
"xyz.openbmc_project.PCIe.PcieData", "GetPendingAttribute");

return;
Expand Down Expand Up @@ -762,6 +780,9 @@ inline void handleBiosAttributeRegistryGet(
return;
}

uint8_t hostNumber = redfish::amd_hpar::hostNumberFromReq(req);
std::string pcieSvc = redfish::amd_hpar::pcieDataService(hostNumber);
std::string pcieObj = redfish::amd_hpar::pcieDataObject(hostNumber);
crow::connections::systemBus->async_method_call(
[asyncResp](const boost::system::error_code ec,
BiosRegistryAttrMap& registryTable) {
Expand Down Expand Up @@ -849,7 +870,7 @@ inline void handleBiosAttributeRegistryGet(
asyncResp->res.jsonValue = orderedRes;
messages::success(asyncResp->res);
},
"xyz.openbmc_project.PCIe", "/xyz/openbmc_project/inventory/PCIe",
pcieSvc, pcieObj,
"xyz.openbmc_project.PCIe.PcieData", "GetBiosRegistryAttribute");
}

Expand Down Expand Up @@ -893,7 +914,8 @@ inline void handleBiosAttributeRegistryPut(
return;
}

setBiosRegistryAttributes(asyncResp, table);
uint8_t hostNumber = redfish::amd_hpar::hostNumberFromReq(req);
setBiosRegistryAttributes(asyncResp, table, hostNumber);
}

inline void requestRoutesBiosAttributeRegistry(App& app)
Expand Down
6 changes: 5 additions & 1 deletion redfish-core/lib/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "bmcweb_config.h"

#include "amd_host_inventory.hpp"
#include "app.hpp"
#include "async_resp.hpp"
#include "dbus_utility.hpp"
Expand Down Expand Up @@ -883,6 +884,9 @@ inline void handleMemoryDevicePost(

OuterMap dimmMap;
dimmMap[dimmId] = dimmDataMap;
uint8_t hostNumber = redfish::amd_hpar::hostNumberFromReq(req);
std::string pcieSvc = redfish::amd_hpar::pcieDataService(hostNumber);
std::string pcieObj = redfish::amd_hpar::pcieDataObject(hostNumber);
crow::connections::systemBus->async_method_call(
[asyncResp](const boost::system::error_code ec) {
if (ec)
Expand All @@ -894,7 +898,7 @@ inline void handleMemoryDevicePost(
messages::success(asyncResp->res);
return;
},
"xyz.openbmc_project.PCIe", "/xyz/openbmc_project/inventory/PCIe",
pcieSvc, pcieObj,
"xyz.openbmc_project.PCIe.PcieData", "SetDimmData", dimmMap);

asyncResp->res.jsonValue["Status"] = "OK";
Expand Down
6 changes: 5 additions & 1 deletion redfish-core/lib/pcie.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "bmcweb_config.h"

#include "amd_host_inventory.hpp"
#include "app.hpp"
#include "async_resp.hpp"
#include "dbus_utility.hpp"
Expand Down Expand Up @@ -678,6 +679,9 @@ inline void handlePCIeDevicePost(

OuterMap pcieMap;
pcieMap[pcieDeviceId] = pcieDataMap;
uint8_t hostNumber = redfish::amd_hpar::hostNumberFromReq(req);
std::string pcieSvc = redfish::amd_hpar::pcieDataService(hostNumber);
std::string pcieObj = redfish::amd_hpar::pcieDataObject(hostNumber);
crow::connections::systemBus->async_method_call(
[asyncResp](const boost::system::error_code ec) {
if (ec)
Expand All @@ -688,7 +692,7 @@ inline void handlePCIeDevicePost(
}
messages::success(asyncResp->res);
},
"xyz.openbmc_project.PCIe", "/xyz/openbmc_project/inventory/PCIe",
pcieSvc, pcieObj,
"xyz.openbmc_project.PCIe.PcieData", "SetPcieData", pcieMap);

asyncResp->res.jsonValue["Status"] = "OK";
Expand Down
Loading