dcmi: get real power cap settings

Now that the user power cap settings are defined, provide
them via the ipmi dcmi interface

Change-Id: I46b0c3f006eee714c7f412f2aec4433e67aeb187
Signed-off-by: Andrew Geissler <andrewg@us.ibm.com>
diff --git a/dcmihandler.cpp b/dcmihandler.cpp
index 4c4f8b7..43c27f8 100644
--- a/dcmihandler.cpp
+++ b/dcmihandler.cpp
@@ -1,10 +1,12 @@
 #include "dcmihandler.hpp"
 #include "host-ipmid/ipmid-api.h"
 #include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/bus.hpp>
+#include "utils.hpp"
 #include <stdio.h>
 #include <string.h>
 #include <stdint.h>
-#include "utils.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 
 using namespace phosphor::logging;
@@ -13,23 +15,99 @@
 
 void register_netfn_dcmi_functions() __attribute__((constructor));
 
+constexpr auto PCAP_SETTINGS_SERVICE = "xyz.openbmc_project.Settings";
+constexpr auto PCAP_PATH    = "/xyz/openbmc_project/control/host0/power_cap";
+constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
+
+constexpr auto POWER_CAP_PROP = "PowerCap";
+constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
+
+using namespace phosphor::logging;
+
+uint32_t getPcap(sdbusplus::bus::bus& bus)
+{
+    auto settingService = ipmi::getService(bus,
+                                           PCAP_PATH,PCAP_SETTINGS_SERVICE);
+
+    auto method = bus.new_method_call(settingService.c_str(),
+                                      PCAP_PATH,
+                                      "org.freedesktop.DBus.Properties",
+                                      "Get");
+
+    method.append(PCAP_INTERFACE, POWER_CAP_PROP);
+    auto reply = bus.call(method);
+
+    if (reply.is_method_error())
+    {
+        log<level::ERR>("Error in getPcap prop");
+        // TODO openbmc/openbmc#851 - Once available, throw returned error
+        // and return IPMI_CC_UNSPECIFIED_ERROR to caller
+        return 0;
+    }
+    sdbusplus::message::variant<uint32_t> pcap;
+    reply.read(pcap);
+
+    return sdbusplus::message::variant_ns::get<uint32_t>(pcap);
+}
+
+bool getPcapEnabled(sdbusplus::bus::bus& bus)
+{
+    auto settingService = ipmi::getService(bus,
+                                           PCAP_PATH,PCAP_SETTINGS_SERVICE);
+
+    auto method = bus.new_method_call(settingService.c_str(),
+                                      PCAP_PATH,
+                                      "org.freedesktop.DBus.Properties",
+                                      "Get");
+
+    method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
+    auto reply = bus.call(method);
+
+    if (reply.is_method_error())
+    {
+        log<level::ERR>("Error in getPcapEnabled prop");
+        // TODO openbmc/openbmc#851 - Once available, throw returned error
+        // and return IPMI_CC_UNSPECIFIED_ERROR to caller
+        return false;
+    }
+    sdbusplus::message::variant<bool> pcapEnabled;
+    reply.read(pcapEnabled);
+
+    return sdbusplus::message::variant_ns::get<bool>(pcapEnabled);
+}
 
 ipmi_ret_t ipmi_dcmi_get_power_limit(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 
                               ipmi_request_t request, ipmi_response_t response, 
                               ipmi_data_len_t data_len, ipmi_context_t context)
 {
+    // Default to no power cap enabled
     ipmi_ret_t rc = IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
 
-    // dcmi-v1-5-rev-spec.pdf 6.6.2.   
-    // This is good enough for OpenBMC support for OpenPOWER based systems
-    // TODO research if more is needed
-    uint8_t data_response[] = { 0xDC, 0x00, 0x00, 0x01, 0x00, 0x00, 
-                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-                                0x00, 0x01};
+    // Get our sdbus object
+    sd_bus *bus = ipmid_get_sd_bus_connection();
+    sdbusplus::bus::bus sdbus {bus};
+
+    // Read our power cap settings
+    auto pcap = getPcap(sdbus);
+    auto pcapEnable = getPcapEnabled(sdbus);
+    if(pcapEnable)
+    {
+        // indicate power cap enabled with success return code
+        rc = IPMI_CC_OK;
+    }
+
+    uint8_t pcapBytes[2] = {0};
+    pcapBytes[1] = (pcap & 0xFF00) >> 8;
+    pcapBytes[0] = pcap & 0xFF;
+    // dcmi-v1-5-rev-spec.pdf 6.6.2.
+    uint8_t data_response[] = { 0xDC, 0x00, 0x00, 0x01, pcapBytes[0],
+                                pcapBytes[1], 0x00, 0x00, 0x00, 0x00, 0x00,
+                                0x00, 0x00, 0x01};
 
 
-
-    printf("IPMI DCMI_GET_POWER_LEVEL\n");
+    log<level::INFO>("IPMI DCMI POWER CAP INFO",
+                     entry("DCMI_PCAP=%u",pcap),
+                     entry("DCMI_PCAP_ENABLE=%u",pcapEnable));
 
     memcpy(response, data_response, sizeof(data_response));
     *data_len = sizeof(data_response);