phosphor: dbus-sensors: Migrate patches to meta-gbmc-staging

These patches were residing in an internal repository. We do not
need to be hide them. We need to share them with external
partners.

Tested:

Verified that the patches are applied correctly.

Verified that the content delivered by the patches
is present on the machine.

Change-Id: Ia309d85fa453983eabd5a2607512223f48de8214
Signed-off-by: Claire Liao <claireliao@google.com>
(cherry picked from commit 5160c029f940c99257883ad85b700f9084e8e6de)
diff --git a/recipes-phosphor/sensors/dbus-sensors/0010-dbus-sensors-Creating-association-between-inventory-.patch b/recipes-phosphor/sensors/dbus-sensors/0010-dbus-sensors-Creating-association-between-inventory-.patch
new file mode 100644
index 0000000..8347433
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0010-dbus-sensors-Creating-association-between-inventory-.patch
@@ -0,0 +1,366 @@
+From 136784e24eddedac053949883247ff6933fcb9e6 Mon Sep 17 00:00:00 2001
+From: Michael Shen <gpgpgp@google.com>
+Date: Tue, 3 Jan 2023 08:38:40 +0000
+Subject: [PATCH 1/3] dbus-sensors: Creating association between inventory and
+ sensor
+
+This change is based on the https://gerrit.openbmc.org/c/openbmc/dbus-sensors/+/53789
+It sets up additional "inventory" association between hwmon sensor and
+its corresponding inventory.
+For example `SBTSI` is the CPU sensor for AMD CPU so we can associate
+all the `SBTSI` sensor to CPU inventory.
+This is used to add the CPU resource to RelatedItems in bmcweb.
+
+Tested:
+```
+$ busctl call --verbose xyz.openbmc_project.ObjectMapper /xyz/openbmc_project/object_mapper xyz.openbmc_project.ObjectMapper GetSubTree sias /xyz/openbmc_project/sensors/temperature/CPU0_T 0 0
+MESSAGE "a{sa{sas}}" {
+        ARRAY "{sa{sas}}" {
+                DICT_ENTRY "sa{sas}" {
+                        STRING "/xyz/openbmc_project/sensors/temperature/CPU0_T/chassis";
+                        ARRAY "{sas}" {
+                                DICT_ENTRY "sas" {
+                                        STRING "xyz.openbmc_project.ObjectMapper";
+                                        ARRAY "s" {
+                                                STRING "xyz.openbmc_project.Association";
+                                        };
+                                };
+                        };
+                };
+                DICT_ENTRY "sa{sas}" {
+                        STRING "/xyz/openbmc_project/sensors/temperature/CPU0_T/inventory";
+                        ARRAY "{sas}" {
+                                DICT_ENTRY "sas" {
+                                        STRING "xyz.openbmc_project.ObjectMapper";
+                                        ARRAY "s" {
+                                                STRING "xyz.openbmc_project.Association";
+                                        };
+                                };
+                        };
+                };
+        };
+};
+
+$ busctl get-property xyz.openbmc_project.ObjectMapper /xyz/openbmc_project/sensors/temperature/CPU0_T/inventory xyz.openbmc_project.Association endpoints
+as 1 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0"
+```
+
+Patch Tracking Bug: b/264604501
+Upstream info / review: go/obmcl/60031
+Upstream-Status: Submitted
+Justification: Pending upstream review
+
+Change-Id: I66d5fc880f79bb504dcceb56aee1c6f3d9df73f5
+Signed-off-by: Michael Shen <gpgpgp@google.com>
+Signed-off-by: Willy Tu <wltu@google.com>
+
+%% original patch: 0010-dbus-sensors-Creating-association-between-inventory-.patch
+---
+ src/HwmonTempMain.cpp   | 136 +++++++++++++++++++++++++++++++++++++++-
+ src/HwmonTempSensor.cpp |  31 +++++++--
+ src/HwmonTempSensor.hpp |   3 +-
+ src/Utils.cpp           |  13 ++++
+ src/Utils.hpp           |   2 +
+ 5 files changed, 176 insertions(+), 9 deletions(-)
+
+diff --git a/src/HwmonTempMain.cpp b/src/HwmonTempMain.cpp
+index 340bf11..642902f 100644
+--- a/src/HwmonTempMain.cpp
++++ b/src/HwmonTempMain.cpp
+@@ -23,6 +23,7 @@
+ #include <boost/container/flat_set.hpp>
+ #include <sdbusplus/asio/connection.hpp>
+ #include <sdbusplus/asio/object_server.hpp>
++#include <sdbusplus/asio/property.hpp>
+ #include <sdbusplus/bus/match.hpp>
+ 
+ #include <array>
+@@ -50,6 +51,7 @@ static constexpr double maxValueTemperature = 127;  // DegreesC
+ static constexpr double minValueTemperature = -128; // DegreesC
+ 
+ namespace fs = std::filesystem;
++namespace rules = sdbusplus::bus::match::rules;
+ 
+ static const I2CDeviceTypeMap sensorTypes{
+     {"DPS310", I2CDeviceType{"dps310", false}},
+@@ -77,6 +79,14 @@ static const I2CDeviceTypeMap sensorTypes{
+     {"W83773G", I2CDeviceType{"w83773g", true}},
+ };
+ 
++boost::container::flat_map<std::string, std::string> inventoryMap;
++
++static const boost::container::flat_map<std::string, std::vector<std::string>,
++                                        std::less<>>
++    sensorTargetMap = {
++        {"SBTSI", {"xyz.openbmc_project.Inventory.Item.Cpu"}},
++};
++
+ static struct SensorParams
+     getSensorParameters(const std::filesystem::path& path)
+ {
+@@ -320,6 +330,109 @@ boost::container::flat_map<std::string,
+     return devices;
+ }
+ 
++void updateLocation(
++    const std::shared_ptr<sdbusplus::asio::connection>& systemBus,
++    std::string_view service, std::string_view path)
++{
++    sdbusplus::message_t getLocation = systemBus->new_method_call(
++        service.data(), path.data(), "org.freedesktop.DBus.Properties", "Get");
++    getLocation.append("xyz.openbmc_project.Inventory.Decorator.LocationCode");
++    getLocation.append("LocationCode");
++    std::variant<std::string> location;
++    try
++    {
++        systemBus->call(getLocation).read(location);
++    }
++    catch (const sdbusplus::exception_t&)
++    {
++        std::cerr << "Failed to get property" << std::endl;
++        return;
++    }
++    inventoryMap[std::get<std::string>(location)] = path;
++}
++
++void getInventory(const std::shared_ptr<sdbusplus::asio::connection>& systemBus,
++                  const std::vector<std::string>& interfaces)
++{
++    static boost::container::flat_map<
++        std::string, std::unique_ptr<sdbusplus::bus::match::match>>
++        matchers;
++
++    static auto handler =
++        [&systemBus, &interfaces](sdbusplus::message::message&) {
++        getInventory(systemBus, interfaces);
++    };
++
++    for (const auto& interface : interfaces)
++    {
++        if (matchers.contains(interface))
++        {
++            continue;
++        }
++
++        matchers[interface] = std::make_unique<sdbusplus::bus::match::match>(
++            *systemBus,
++            rules::interfacesAdded() + rules::interface(interface) +
++                rules::path_namespace(inventoryPath),
++            handler);
++    }
++
++    sdbusplus::message_t getSubTree = systemBus->new_method_call(
++        mapper::busName, mapper::path, mapper::interface, mapper::subtree);
++    getSubTree.append(inventoryPath);
++    getSubTree.append(0);
++    getSubTree.append(interfaces);
++    GetSubTreeType subtree;
++    try
++    {
++        systemBus->call(getSubTree).read(subtree);
++    }
++    catch (const sdbusplus::exception_t&)
++    {
++        std::cerr << "Failed to get subtree\n";
++        return;
++    }
++
++    for (const auto& [path, services] : subtree)
++    {
++        for (const auto& [service, interfaces] : services)
++        {
++            if (std::find(
++                    interfaces.begin(), interfaces.end(),
++                    "xyz.openbmc_project.Inventory.Decorator.LocationCode") ==
++                interfaces.end())
++            {
++                continue;
++            }
++            updateLocation(systemBus, service, path);
++        }
++    }
++}
++
++// This function assumes that `LocationCode` is always a substring of its
++// corresponding `sensorName`. For example if the `LocationCode` of a cpu sensor
++// is `CPU1`. Then "Die_CPU1", "CPU1", "CPU1_T", "this_is_cpu1_sensor" are all
++// valid `sensorName`.
++std::string findInventoryPath(const std::string& sensorName)
++{
++    auto findInventoryPath =
++        std::find_if(inventoryMap.begin(), inventoryMap.end(),
++                     [&sensorName](const auto& e) {
++        // ex: e.first(LocationCode)="CPU1" => search="(CPU1$|CPU1[^0-9].*$)"
++        // This will avoid "CPU11", "CPU12" ... to be matched
++        std::regex locationReg("(" + e.first + "$|" + e.first + "[^0-9].*$)",
++                               std::regex::icase);
++        return std::regex_match(sensorName, locationReg);
++        });
++
++    if (findInventoryPath == inventoryMap.end())
++    {
++        std::cerr << "Inventory not found for " << sensorName << "\n";
++        return "";
++    }
++    return findInventoryPath->second;
++}
++
+ void createSensors(
+     boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
+     boost::container::flat_map<std::string, std::shared_ptr<HwmonTempSensor>>&
+@@ -501,11 +614,20 @@ void createSensors(
+                 }
+                 else
+                 {
++                    std::string inventoryPath{};
++                    const auto& foundIfaces =
++                        sensorTargetMap.find(getLastNameFromIface(sensorType));
++                    if (foundIfaces != sensorTargetMap.end())
++                    {
++                        getInventory(dbusConnection, foundIfaces->second);
++                        inventoryPath = findInventoryPath(sensorName);
++                    }
++
+                     sensor = std::make_shared<HwmonTempSensor>(
+                         *hwmonFile, sensorType, objectServer, dbusConnection,
+                         io, sensorName, std::move(sensorThresholds),
+                         thisSensorParameters, pollRate, interfacePath,
+-                        readState, i2cDev);
++                        readState, i2cDev, inventoryPath);
+                     sensor->setupRead();
+                 }
+             }
+@@ -560,11 +682,21 @@ void createSensors(
+                     }
+                     else
+                     {
++                        std::string inventoryPath{};
++                        const auto& foundIfaces = sensorTargetMap.find(
++                            getLastNameFromIface(sensorType));
++                        if (foundIfaces != sensorTargetMap.end())
++                        {
++                            getInventory(dbusConnection, foundIfaces->second);
++                            inventoryPath = findInventoryPath(sensorName);
++                        }
++
+                         sensor = std::make_shared<HwmonTempSensor>(
+                             *hwmonFile, sensorType, objectServer,
+                             dbusConnection, io, sensorName,
+                             std::move(thresholds), thisSensorParameters,
+-                            pollRate, interfacePath, readState, i2cDev);
++                            pollRate, interfacePath, readState, i2cDev,
++                            inventoryPath);
+                         sensor->setupRead();
+                     }
+                 }
+diff --git a/src/HwmonTempSensor.cpp b/src/HwmonTempSensor.cpp
+index 180c0c8..f92b8ab 100644
+--- a/src/HwmonTempSensor.cpp
++++ b/src/HwmonTempSensor.cpp
+@@ -23,6 +23,7 @@
+ #include <sdbusplus/asio/object_server.hpp>
+ 
+ #include <charconv>
++#include <filesystem>
+ #include <iostream>
+ #include <istream>
+ #include <limits>
+@@ -31,6 +32,8 @@
+ #include <utility>
+ #include <vector>
+ 
++namespace fs = std::filesystem;
++
+ // Temperatures are read in milli degrees Celsius, we need degrees Celsius.
+ // Pressures are read in kilopascal, we need Pascals.  On D-Bus for Open BMC
+ // we use the International System of Units without prefixes.
+@@ -48,7 +51,8 @@ HwmonTempSensor::HwmonTempSensor(
+     std::vector<thresholds::Threshold>&& thresholdsIn,
+     const struct SensorParams& thisSensorParameters, const float pollRate,
+     const std::string& sensorConfiguration, const PowerState powerState,
+-    const std::shared_ptr<I2CDevice>& i2cDevice) :
++    const std::shared_ptr<I2CDevice>& i2cDevice,
++    const std::string& inventoryPath) :
+     Sensor(boost::replace_all_copy(sensorName, " ", "_"),
+            std::move(thresholdsIn), sensorConfiguration, objectType, false,
+            false, thisSensorParameters.maxValue, thisSensorParameters.minValue,
+@@ -73,11 +77,26 @@ HwmonTempSensor::HwmonTempSensor(
+                                            name,
+                                        interface);
+     }
+-    association = objectServer.add_interface("/xyz/openbmc_project/sensors/" +
+-                                                 thisSensorParameters.typeName +
+-                                                 "/" + name,
+-                                             association::interface);
+-    setInitialProperties(thisSensorParameters.units);
++
++    if (inventoryPath.empty())
++    {
++        association = objectServer.add_interface(
++            "/xyz/openbmc_project/sensors/" + thisSensorParameters.typeName +
++                "/" + name,
++            association::interface);
++        setInitialProperties(thisSensorParameters.units);
++    }
++    else
++    {
++        setInitialProperties(thisSensorParameters.units);
++        association = objectServer.add_interface(
++            "/xyz/openbmc_project/sensors/" + thisSensorParameters.typeName +
++                "/" + name,
++            association::interface);
++        std::string chassisPath(
++            fs::path(sensorConfiguration).parent_path().string());
++        setInventoryAssociation(association, inventoryPath, chassisPath);
++    }
+ }
+ 
+ bool HwmonTempSensor::isActive()
+diff --git a/src/HwmonTempSensor.hpp b/src/HwmonTempSensor.hpp
+index d45dafd..f3937f4 100644
+--- a/src/HwmonTempSensor.hpp
++++ b/src/HwmonTempSensor.hpp
+@@ -33,7 +33,8 @@ class HwmonTempSensor :
+                     const struct SensorParams& thisSensorParameters,
+                     float pollRate, const std::string& sensorConfiguration,
+                     PowerState powerState,
+-                    const std::shared_ptr<I2CDevice>& i2cDevice);
++                    const std::shared_ptr<I2CDevice>& i2cDevice,
++                    const std::string& inventoryPath);
+     ~HwmonTempSensor() override;
+     void setupRead(void);
+     void activate(const std::string& newPath,
+diff --git a/src/Utils.cpp b/src/Utils.cpp
+index d659d37..1a92add 100644
+--- a/src/Utils.cpp
++++ b/src/Utils.cpp
+@@ -850,3 +850,16 @@ std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
+     }
+     return setupPropertiesChangedMatches(bus, {types}, handler);
+ }
++
++std::string getLastNameFromIface(const std::string& iface)
++{
++    std::regex itemIfaceReg("^(.*?\\.)*(.*?)$");
++    std::smatch match;
++
++    if (std::regex_search(iface, match, itemIfaceReg))
++    {
++        return match[match.size() - 1];
++    }
++
++    return "";
++}
+diff --git a/src/Utils.hpp b/src/Utils.hpp
+index d7a08db..714c108 100644
+--- a/src/Utils.hpp
++++ b/src/Utils.hpp
+@@ -391,3 +391,5 @@ std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
+     setupPropertiesChangedMatches(
+         sdbusplus::asio::connection& bus, std::span<const char* const> types,
+         const std::function<void(sdbusplus::message_t&)>& handler);
++
++std::string getLastNameFromIface(const std::string& iface);
+-- 
+2.35.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors_%.bbappend b/recipes-phosphor/sensors/dbus-sensors_%.bbappend
index ae21eae..9c91791 100644
--- a/recipes-phosphor/sensors/dbus-sensors_%.bbappend
+++ b/recipes-phosphor/sensors/dbus-sensors_%.bbappend
@@ -10,6 +10,7 @@
   file://0102-RedfishSensor-Network-error-handling-teardown.patch \
   file://0103-RedfishSensor-Intentionally-drop-reported-stale.patch \
   file://0104-RedfishSensor-Port-feature-and-other-cleanups.patch \
+  file://0010-dbus-sensors-Creating-association-between-inventory-.patch \
 "
 
 # gBMC NVMe-MI support begins