Processor: Add processor throttle status

- Update Processor Schema to 18.0
- Add processor throttle status and cause
  https://gerrit.openbmc.org/c/openbmc/phosphor-dbus-interfaces/+/63063
  Throttled: An indication of whether the processor is throttled.
  ThrottledCauses: An array of reasons that the processor is throttled.

Ran validator and no new errors were found.

Change-Id: Ia4a58ae0f26ffc6177f418420ba45063471323da
Signed-off-by: Chris Cain <cjcain@us.ibm.com>
diff --git a/redfish-core/lib/processor.hpp b/redfish-core/lib/processor.hpp
index 19b059a..90938c9 100644
--- a/redfish-core/lib/processor.hpp
+++ b/redfish-core/lib/processor.hpp
@@ -19,6 +19,7 @@
 #include "dbus_singleton.hpp"
 #include "dbus_utility.hpp"
 #include "error_messages.hpp"
+#include "generated/enums/processor.hpp"
 #include "health.hpp"
 #include "query.hpp"
 #include "registries/privilege_registry.hpp"
@@ -292,6 +293,100 @@
         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
 }
 
+/**
+ * @brief Translates throttle cause DBUS property to redfish.
+ *
+ * @param[in] dbusSource    The throttle cause from DBUS
+ *
+ * @return Returns as a string, the throttle cause in Redfish terms. If
+ * translation cannot be done, returns "Unknown" throttle reason.
+ */
+inline processor::ThrottleCause
+    dbusToRfThrottleCause(const std::string& dbusSource)
+{
+    if (dbusSource ==
+        "xyz.openbmc_project.Control.Power.Throttle.ThrottleReasons.ClockLimit")
+    {
+        return processor::ThrottleCause::ClockLimit;
+    }
+    if (dbusSource ==
+        "xyz.openbmc_project.Control.Power.Throttle.ThrottleReasons.ManagementDetectedFault")
+    {
+        return processor::ThrottleCause::ManagementDetectedFault;
+    }
+    if (dbusSource ==
+        "xyz.openbmc_project.Control.Power.Throttle.ThrottleReasons.PowerLimit")
+    {
+        return processor::ThrottleCause::PowerLimit;
+    }
+    if (dbusSource ==
+        "xyz.openbmc_project.Control.Power.Throttle.ThrottleReasons.ThermalLimit")
+    {
+        return processor::ThrottleCause::ThermalLimit;
+    }
+    if (dbusSource ==
+        "xyz.openbmc_project.Control.Power.Throttle.ThrottleReasons.Unknown")
+    {
+        return processor::ThrottleCause::Unknown;
+    }
+    return processor::ThrottleCause::Invalid;
+}
+
+inline void
+    readThrottleProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
+                           const boost::system::error_code& ec,
+                           const dbus::utility::DBusPropertiesMap& properties)
+{
+    if (ec)
+    {
+        BMCWEB_LOG_ERROR << "Processor Throttle getAllProperties error " << ec;
+        messages::internalError(aResp->res);
+        return;
+    }
+
+    const bool* status = nullptr;
+    const std::vector<std::string>* causes = nullptr;
+
+    if (!sdbusplus::unpackPropertiesNoThrow(dbus_utils::UnpackErrorPrinter(),
+                                            properties, "Throttled", status,
+                                            "ThrottleCauses", causes))
+    {
+        messages::internalError(aResp->res);
+        return;
+    }
+
+    aResp->res.jsonValue["Throttled"] = *status;
+    nlohmann::json::array_t rCauses;
+    for (const std::string& cause : *causes)
+    {
+        processor::ThrottleCause rfCause = dbusToRfThrottleCause(cause);
+        if (rfCause == processor::ThrottleCause::Invalid)
+        {
+            messages::internalError(aResp->res);
+            return;
+        }
+
+        rCauses.emplace_back(rfCause);
+    }
+    aResp->res.jsonValue["ThrottleCauses"] = std::move(rCauses);
+}
+
+inline void
+    getThrottleProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
+                          const std::string& service,
+                          const std::string& objectPath)
+{
+    BMCWEB_LOG_DEBUG << "Get processor throttle resources";
+
+    sdbusplus::asio::getAllProperties(
+        *crow::connections::systemBus, service, objectPath,
+        "xyz.openbmc_project.Control.Power.Throttle",
+        [aResp](const boost::system::error_code& ec,
+                const dbus::utility::DBusPropertiesMap& properties) {
+        readThrottleProperties(aResp, ec, properties);
+        });
+}
+
 inline void getCpuAssetData(std::shared_ptr<bmcweb::AsyncResp> aResp,
                             const std::string& service,
                             const std::string& objPath)
@@ -684,7 +779,7 @@
     BMCWEB_LOG_DEBUG << "Get available system processor resources.";
 
     // GetSubTree on all interfaces which provide info about a Processor
-    constexpr std::array<std::string_view, 8> interfaces = {
+    constexpr std::array<std::string_view, 9> interfaces = {
         "xyz.openbmc_project.Common.UUID",
         "xyz.openbmc_project.Inventory.Decorator.Asset",
         "xyz.openbmc_project.Inventory.Decorator.Revision",
@@ -692,7 +787,8 @@
         "xyz.openbmc_project.Inventory.Decorator.LocationCode",
         "xyz.openbmc_project.Inventory.Item.Accelerator",
         "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
-        "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier"};
+        "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier",
+        "xyz.openbmc_project.Control.Power.Throttle"};
     dbus::utility::getSubTree(
         "/xyz/openbmc_project/inventory", 0, interfaces,
         [resp, processorId, handler = std::forward<Handler>(handler)](
@@ -794,6 +890,10 @@
             {
                 getCpuUniqueId(aResp, serviceName, objectPath);
             }
+            else if (interface == "xyz.openbmc_project.Control.Power.Throttle")
+            {
+                getThrottleProperties(aResp, serviceName, objectPath);
+            }
         }
     }
 }
@@ -1260,7 +1360,7 @@
             boost::beast::http::field::link,
             "</redfish/v1/JsonSchemas/Processor/Processor.json>; rel=describedby");
         asyncResp->res.jsonValue["@odata.type"] =
-            "#Processor.v1_11_0.Processor";
+            "#Processor.v1_18_0.Processor";
         asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
             "/redfish/v1/Systems/system/Processors/{}", processorId);