gpio-presence: track parent inventory compatible
When detecting multiple instances of a device such as a fan module
```
{
"Exposes": [
{
"Name": "FAN1",
"PresencePinNames": [
"FAN1_PRSNT"
],
"PresencePinValues": [
1
],
"Type": "GPIODeviceDetect"
},
{
"Name": "FAN2",
"PresencePinNames": [
"FAN2_PRSNT"
],
"PresencePinValues": [
1
],
"Type": "GPIODeviceDetect"
}
],
"Name": "Minerva Fan Board 6",
"Probe": [
"xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'Minerva Fan Board.*', 'PRODUCT_MANUFACTURER': 'Quanta', 'BUS': 21, 'BOARD_INFO_AM4': 'pwr-silergy'})",
"OR",
"xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'Minerva Fan Board DVT', 'PRODUCT_MANUFACTURER': 'Quanta', 'BUS': 21, 'BOARD_PART_NUMBER': '3XF0MFB0030'})"
],
"Type": "Board",
"xyz.openbmc_project.Inventory.Decorator.Asset": {
"BuildDate": "$BOARD_MANUFACTURE_DATE",
"Manufacturer": "$BOARD_MANUFACTURER",
"Model": "$BOARD_PRODUCT_NAME",
"PartNumber": "$BOARD_PART_NUMBER",
"SerialNumber": "$BOARD_SERIAL_NUMBER",
"SparePartNumber": "$BOARD_INFO_AM1"
},
"xyz.openbmc_project.Inventory.Decorator.AssetTag": {
"AssetTag": "$PRODUCT_ASSET_TAG"
},
"xyz.openbmc_project.Inventory.Decorator.Compatible": {
"Names": [
"com.meta.Hardware.Minerva.FanBoard"
]
}
}
```
we want to use a single configuration file for that FRU to avoid
duplication.
```
{
"Exposes": [],
"Name": "$Name",
"Probe": [
"xyz.openbmc_project.Inventory.Source.DevicePresence({'Name': 'FAN*'})"
],
"Type": "Board",
"xyz.openbmc_project.Inventory.Decorator.Asset": {
"Manufacturer": "Unknown",
"Model": "Unknown",
"PartNumber": "Unknown",
"SerialNumber": "Unknown",
"SparePartNumber": "05-100051"
}
}
```
That creates the requirement to have `Name` property to be something
which can show up for example in the fan (or whichever) inventory.
This requirement conflicts with the requirement for `Probe` statements
to be unique and not trigger any unintended probing of unrelated
configurations.
Since `FAN 2` is a good name to use in context of a single system, but
not sufficiently unique to probe a configuration.
This patch populates a `Compatible` field on the
`xyz.openbmc_project.Inventory.Source.DevicePresence` interface which
allows to rewrite above `Probe` statement as:
```
"xyz.openbmc_project.Inventory.Source.DevicePresence({'Name': 'FAN*', 'Compatible': 'com.meta.Hardware.Minerva*'})"
```
which will be unique and not probe accidentally on other systems.
The PDI change is [4].
The value for `Compatible` field is taken from the parent inventory item
object path, which can have an optional
"xyz.openbmc_project.Inventory.Decorator.Compatible" configured.
From my perspective, entity-manager does not currently support probing
on properties which have an array type [3], so we simply take the first
value if there are multiple compatible strings on the decorator.
In case there is no such decorator, the `Compatible` string will be
empty.
Alternatives considered:
- configuring a `Compatible` property on `GPIODeviceDetect` schema.
This creates configuration bloat as all such instances are already
identified by `Name` in context of a single system.
- expanding `Probe` statement to also probe on the baseboard.
This is undesirable as currently `Probe` statement is kind of broken
[2], does not support nested expressions and also does not handle
boolean operator precedence correctly.
Tested:
Unit Tests have been adjusted.
On Tyan S8030 added following example record for some gpio.
```
{
"Name": "ExampleDevice",
"PresencePinNames": [ "BMC_SPD_SEL" ],
"PresencePinValues": [ 0 ],
"Type": "GPIODeviceDetect"
},
```
compatible decorator is not set, so compatible is empty when it detects
the Example Device.
```
xyz.openbmc_project.Inventory.Source.DevicePresence interface - - -
.Compatible property s "" emits-change writable
.Name property s "ExampleDevice" emits-change writable
```
Adding following compatible decorator
```
"xyz.openbmc_project.Inventory.Decorator.Compatible": {
"Names": [
"com.tyan.Hardware.Mainboard.S8030",
"com.tyan.Hardware.Mainboard.S8030GM"
]
}
```
And the daemon picks it up
```
Aug 22 14:43:35 s8030-bmc-30303035c0c1 gpio-presence-sensor[7336]: found configuration interface at xyz.openbmc_project.EntityManager /xyz/openbmc_project/inventory/system/board/Tyan_S8030_Baseboard/ExampleDevice xyz.openbmc_project.Configuration.GPIODeviceDetect
Aug 22 14:43:35 s8030-bmc-30303035c0c1 gpio-presence-sensor[7336]: Found 'Compatible' decorator on parent inventory path of /xyz/openbmc_project/inventory/system/board/Tyan_S8030_Baseboard/ExampleDevice
Aug 22 14:43:35 s8030-bmc-30303035c0c1 gpio-presence-sensor[7336]: adding configuration for /xyz/openbmc_project/inventory/system/board/Tyan_S8030_Baseboard/ExampleDevice
Aug 22 14:43:36 s8030-bmc-30303035c0c1 gpio-presence-sensor[7336]: found valid configuration at object path /xyz/openbmc_project/inventory/system/board/Tyan_S8030_Baseboard/ExampleDevice
Aug 22 14:43:36 s8030-bmc-30303035c0c1 gpio-presence-sensor[7336]: Watching gpio events for BMC_SPD_SEL
Aug 22 14:43:36 s8030-bmc-30303035c0c1 gpio-presence-sensor[7336]: GPIO line BMC_SPD_SEL went low
Aug 22 14:43:36 s8030-bmc-30303035c0c1 gpio-presence-sensor[7336]: Updating dbus interface for config ExampleDevice
Aug 22 14:43:36 s8030-bmc-30303035c0c1 gpio-presence-sensor[7336]: Detected ExampleDevice as present, adding dbus interface
```
Then the Compatible string is exposed as expected
```
xyz.openbmc_project.Inventory.Source.DevicePresence interface - - -
.Compatible property s "com.tyan.Hardware.Mainboard.S8030" emits-change writable
.Name property s "ExampleDevice" emits-change writable
```
References:
[1] https://gerrit.openbmc.org/c/openbmc/entity-manager/+/82819
[2] https://github.com/openbmc/entity-manager/blob/e86be7c648b6fa6e457928b4348e561b852b79bb/src/entity_manager/perform_probe.cpp#L165
[3] https://github.com/openbmc/entity-manager/blob/e86be7c648b6fa6e457928b4348e561b852b79bb/src/utils.cpp#L116
[4] https://gerrit.openbmc.org/c/openbmc/phosphor-dbus-interfaces/+/83061
Change-Id: I9eec81c59d1910a05bf0776f9732281473861c63
Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
diff --git a/src/gpio-presence/device_presence.cpp b/src/gpio-presence/device_presence.cpp
index 1402996..11a76a9 100644
--- a/src/gpio-presence/device_presence.cpp
+++ b/src/gpio-presence/device_presence.cpp
@@ -25,8 +25,10 @@
DevicePresence::DevicePresence(
sdbusplus::async::context& ctx, const std::vector<std::string>& gpioNames,
const std::vector<uint64_t>& gpioValues, const std::string& deviceName,
- const std::unordered_map<std::string, bool>& gpioState) :
- deviceName(deviceName), gpioState(gpioState), ctx(ctx)
+ const std::unordered_map<std::string, bool>& gpioState,
+ const std::vector<std::string>& parentInvCompatible) :
+ deviceName(deviceName), gpioState(gpioState), ctx(ctx),
+ parentInventoryCompatible(parentInvCompatible)
{
for (size_t i = 0; i < gpioNames.size(); i++)
{
@@ -92,8 +94,13 @@
info("Detected {NAME} as present, adding dbus interface", "NAME",
deviceName);
+ const std::string firstCompatible =
+ parentInventoryCompatible.empty() ? ""
+ : parentInventoryCompatible[0];
+
detectedIface = std::make_unique<DevicePresenceInterface>(
- ctx, objPath.str.c_str(), DevicePresenceProperties{deviceName});
+ ctx, objPath.str.c_str(),
+ DevicePresenceProperties{deviceName, firstCompatible});
detectedIface->emit_added();
}