Add i2c voltage regulator updater
- /i2c-vr: Classes following the design in [1]
- /i2c-vr/vr.cpp, vr.hpp: General representation of a voltage regulators
communication interface
- /vr-i2c/xdpe1x2xx: Support for Infineon XDPE1x2xx class of voltage
regulators
- /common/i2c/: Basic I2C communication interface
The configuration of a voltage regulator relies on the EM-Schema in [2]
1: https://github.com/openbmc/docs/blob/master/designs/code-update.md
2: https://gerrit.openbmc.org/c/openbmc/entity-manager/+/77463
Tested on QEMU/Yosemite4:
1. Display the firmware inventory
```
curl --insecure --user root:0penBmc \
https://127.0.0.1:2443/redfish/v1/UpdateService/FirmwareInventory
```
Output:
```
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory",
"@odata.type": "#SoftwareInventoryCollection.SoftwareInventoryCollection",
"Members": [
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/16bae6fd"
},
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/DummyDeviceFirmwareName_6637"
},
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Management_Board_cpld"
},
{...}
```
2. Query voltage regulator version
The dummy device sets the default version to 0xBEEF (Decimal: 48879)
```
curl --insecure --user root:0penBmc \
https://127.0.0.1:2443/redfish/v1/UpdateService/FirmwareInventory/
DummyDeviceFirmwareName_4390
```
Output:
```
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/DummyDeviceFirmwareName_4390",
"@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
"Description": "Other image",
"Id": "DummyDeviceFirmwareName_4390",
"Name": "Software Inventory",
"Status": {
"Health": "Warning",
"HealthRollup": "OK",
"State": "Disabled"
},
"Updateable": false,
"Version": "48879"
}
```
3. Trigger the update
```
curl -k --insecure --user root:0penBmc \
-H "Content-Type:multipart/form-data" \
-X POST \
-F UpdateParameters="{\"Targets\":[\"/redfish/v1/UpdateService/FirmwareInventory/DummyDeviceFirmwareName_4390\"],\"@Redfish.OperationApplyTime\":\"Immediate\"};type=application/json" \
-F "UpdateFile=@fw_vr_update.bin;type=application/octet-stream" \
https://127.0.0.1:2443/redfish/v1/UpdateService/update
```
4. Task is returned
```
{
"@odata.id": "/redfish/v1/TaskService/Tasks/0",
"@odata.type": "#Task.v1_4_3.Task",
"Id": "0",
"TaskState": "Running",
"TaskStatus": "OK"
}
```
5. Query the task
```
curl --insecure --user root:0penBmc \
https://127.0.0.1:2443/redfish/v1/TaskService/Tasks/0
```
Output:
```
{
"@odata.id": "/redfish/v1/TaskService/Tasks/0",
"@odata.type": "#Task.v1_4_3.Task",
"EndTime": "2025-03-10T13:47:34+00:00",
"HidePayload": false,
"Id": "0",
"Messages": [
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The task with Id '0' has started.",
"MessageArgs": [
"0"
],
"MessageId": "TaskEvent.1.0.TaskStarted",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The task with Id '0' has completed.",
"MessageArgs": [
"0"
],
"MessageId": "TaskEvent.1.0.TaskCompletedOK",
"MessageSeverity": "OK",
"Resolution": "None."
}
],
"Name": "Task 0",
"Payload": {
"HttpHeaders": [],
"HttpOperation": "POST",
"JsonBody": "null",
"TargetUri": "/redfish/v1/UpdateService/update"
},
"PercentComplete": 0,
"StartTime": "2025-03-10T13:47:34+00:00",
"TaskMonitor": "/redfish/v1/TaskService/TaskMonitors/0",
"TaskState": "Completed",
"TaskStatus": "OK"
}
```
6. Display fw inventory after update
```
curl --insecure --user root:0penBmc \
https://127.0.0.1:2443/redfish/v1/UpdateService/FirmwareInventory
```
Output:
```
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory",
"@odata.type": "#SoftwareInventoryCollection.SoftwareInventoryCollection",
"Members": [
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/16bae6fd"
},
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/DummyDeviceFirmwareName_282"
},
{...}
}
```
7. Query the new fw version.
The version is 'mycompversion' since that's what has been set in the
pldm fw update package for testing.
```
curl --insecure --user root:0penBmc \
https://127.0.0.1:2443/redfish/v1/UpdateService/FirmwareInventory/
DummyDeviceFirmwareName_282
```
Output:
```
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/DummyDeviceFirmwareName_282",
"@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
"Description": "Other image",
"Id": "DummyDeviceFirmwareName_282",
"Name": "Software Inventory",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"Updateable": false,
"Version": "mycompversion"
}
```
8. Update in progress error
```
curl -k --insecure --user root:0penBmc \
-H "Content-Type:multipart/form-data" \
-X POST \
-F UpdateParameters="{\"Targets\":[\"/redfish/v1/UpdateService/FirmwareInventory/${TARGET}\"],\"@Redfish.OperationApplyTime\":\"Immediate\"};type=application/json" \
-F "UpdateFile=@${FWPATH};type=application/octet-stream" \
https://127.0.0.1:2443/redfish/v1/UpdateService/update
```
Output:
```
{
"error": {
"@Message.ExtendedInfo": [
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The request failed due to an internal service error. The service is still operational.",
"MessageArgs": [],
"MessageId": "Base.1.19.InternalError",
"MessageSeverity": "Critical",
"Resolution": "Resubmit the request. If the problem persists, consider resetting the service."
}
],
"code": "Base.1.19.InternalError",
"message": "The request failed due to an internal service error. The service is still operational."
}
```
Change-Id: I2e11a6c10ae40ed7719ceb86dfd6a38dd5b27017
Signed-off-by: Christopher Meis <christopher.meis@9elements.com>
diff --git a/i2c-vr/i2cvr_software_manager.cpp b/i2c-vr/i2cvr_software_manager.cpp
new file mode 100644
index 0000000..4c9d398
--- /dev/null
+++ b/i2c-vr/i2cvr_software_manager.cpp
@@ -0,0 +1,115 @@
+#include "i2cvr_software_manager.hpp"
+
+#include "common/include/dbus_helper.hpp"
+#include "common/include/software_manager.hpp"
+#include "i2cvr_device.hpp"
+#include "vr.hpp"
+
+#include <phosphor-logging/lg2.hpp>
+#include <sdbusplus/async.hpp>
+#include <sdbusplus/bus.hpp>
+#include <xyz/openbmc_project/ObjectMapper/client.hpp>
+
+#include <cstdint>
+
+PHOSPHOR_LOG2_USING;
+
+namespace VR = phosphor::software::VR;
+namespace I2CDevice = phosphor::software::i2c_vr::device;
+namespace SoftwareInf = phosphor::software;
+namespace ManagerInf = phosphor::software::manager;
+
+const std::string configDBusName = "I2CVR";
+const std::vector<std::string> emConfigTypes = {"XDPE1X2XXFirmware",
+ "DummyDeviceFirmware"};
+
+I2CVRSoftwareManager::I2CVRSoftwareManager(sdbusplus::async::context& ctx) :
+ ManagerInf::SoftwareManager(ctx, configDBusName)
+{}
+
+void I2CVRSoftwareManager::start()
+{
+ std::vector<std::string> configIntfs;
+ configIntfs.reserve(emConfigTypes.size());
+ for (auto& name : emConfigTypes)
+ {
+ configIntfs.push_back("xyz.openbmc_project.Configuration." + name);
+ }
+
+ ctx.spawn(initDevices(configIntfs));
+ ctx.run();
+}
+
+// NOLINTBEGIN(readability-static-accessed-through-instance)
+sdbusplus::async::task<bool> I2CVRSoftwareManager::initDevice(
+ const std::string& service, const std::string& path, SoftwareConfig& config)
+// NOLINTEND(readability-static-accessed-through-instance)
+{
+ std::string configIface =
+ "xyz.openbmc_project.Configuration." + config.configType;
+
+ std::optional<uint64_t> busNum = co_await dbusGetRequiredProperty<uint64_t>(
+ ctx, service, path, configIface, "Bus");
+ std::optional<uint64_t> address =
+ co_await dbusGetRequiredProperty<uint64_t>(ctx, service, path,
+ configIface, "Address");
+ std::optional<std::string> vrChipType =
+ co_await dbusGetRequiredProperty<std::string>(ctx, service, path,
+ configIface, "Type");
+
+ if (!busNum.has_value() || !address.has_value() || !vrChipType.has_value())
+ {
+ error("missing config property");
+ co_return false;
+ }
+
+ VR::VRType vrType;
+ if (!VR::stringToEnum(vrChipType.value(), vrType))
+ {
+ error("unknown voltage regulator type: {TYPE}", "TYPE",
+ vrChipType.value());
+ co_return false;
+ }
+
+ lg2::debug(
+ "[config] Voltage regulator device type: {TYPE} on Bus: {BUS} at Address: {ADDR}",
+ "TYPE", vrChipType.value(), "BUS", busNum.value(), "ADDR",
+ address.value());
+
+ auto i2cDevice = std::make_unique<I2CDevice::I2CVRDevice>(
+ ctx, vrType, static_cast<uint16_t>(busNum.value()),
+ static_cast<uint16_t>(address.value()), config, this);
+
+ std::unique_ptr<SoftwareInf::Software> software =
+ std::make_unique<SoftwareInf::Software>(ctx, *i2cDevice);
+
+ uint32_t sum;
+ if (!(co_await i2cDevice->getVersion(&sum)))
+ {
+ error("unable to obtain Version/CRC from voltage regulator");
+ co_return false;
+ }
+
+ software->setVersion(std::to_string(sum));
+
+ std::set<RequestedApplyTimes> allowedApplyTime = {
+ RequestedApplyTimes::Immediate, RequestedApplyTimes::OnReset};
+
+ software->enableUpdate(allowedApplyTime);
+
+ i2cDevice->softwareCurrent = std::move(software);
+
+ devices.insert({config.objectPath, std::move(i2cDevice)});
+
+ co_return true;
+}
+
+int main()
+{
+ sdbusplus::async::context ctx;
+
+ I2CVRSoftwareManager i2cVRSoftwareManager(ctx);
+
+ i2cVRSoftwareManager.start();
+ return 0;
+}