psu-ng: Set the power-config-full-load GPIO

The power-config-full-load GPIO is an optional GPIO that communicates to
the HW the number of expected number of working PSUs. Reference:
https://github.com/openbmc/docs/commit/2cbf57a8a0bb8d95b0e19b7fc27c4f95cbd8609a

If the system implements this GPIO, set it to the appropriate value when
the psu monitor app starts, and every time the system powers on in case
the number of PSUs was changed when the system was powered off.

In the GPIOReader constructor, move the error message from a journal log
to the exception, otherwise this journal log will show up on all systems
that do not implement this GPIO.

Tested:

Verified the correct value was set by reading the GPIO after
writing by calling line.get_value() during testing.

Verified the GPIOReader only displays the error message when a
GPIO does not exist and the exception is not caught, no error messages
are displayed for a missing power-config-full-load GPIO:
Oct 14 20:54:27 p10bmc phosphor-psu-monitor[1152]: Failed to find
line: Line does not exist: test-gpio
Oct 14 20:54:27 p10bmc systemd[1]: phosphor-psu-monitor.service: Main
process exited, code=exited, status=254/n/a

Change-Id: Ifdcd9f552c28cec860b9b65a1133e179683fb0db
Signed-off-by: Adriana Kobylak <anoo@us.ibm.com>
diff --git a/phosphor-power-supply/psu_manager.cpp b/phosphor-power-supply/psu_manager.cpp
index 78d380a..257fdfb 100644
--- a/phosphor-power-supply/psu_manager.cpp
+++ b/phosphor-power-supply/psu_manager.cpp
@@ -47,6 +47,16 @@
     validationTimer = std::make_unique<utility::Timer<ClockId::Monotonic>>(
         e, std::bind(&PSUManager::validateConfig, this));
 
+    try
+    {
+        powerConfigGPIO = createGPIO("power-config-full-load");
+    }
+    catch (const std::exception& e)
+    {
+        // Ignore error, GPIO may not be implemented in this system.
+        powerConfigGPIO = nullptr;
+    }
+
     // Subscribe to power state changes
     powerService = util::getService(POWER_OBJ_PATH, POWER_IFACE, bus);
     powerOnMatch = std::make_unique<sdbusplus::bus::match_t>(
@@ -329,6 +339,7 @@
             powerOn = true;
             validationTimer->restartOnce(validationTimeout);
             clearFaults();
+            setPowerConfigGPIO();
         }
         else
         {
@@ -627,4 +638,32 @@
     return true;
 }
 
+void PSUManager::setPowerConfigGPIO()
+{
+    if (!powerConfigGPIO)
+    {
+        return;
+    }
+
+    std::string model{};
+    std::map<std::string, std::string> additionalData;
+    if (!validateModelName(model, additionalData))
+    {
+        return;
+    }
+
+    auto config = supportedConfigs.find(model);
+    if (config != supportedConfigs.end())
+    {
+        // The power-config-full-load is an open drain GPIO. Set it to low (0)
+        // if the supported configuration indicates that this system model
+        // expects the maximum number of power supplies (full load set to true).
+        // Else, set it to high (1), this is the default.
+        auto powerConfigValue =
+            (config->second.powerConfigFullLoad == true ? 0 : 1);
+        auto flags = gpiod::line_request::FLAG_OPEN_DRAIN;
+        powerConfigGPIO->write(powerConfigValue, flags);
+    }
+}
+
 } // namespace phosphor::power::manager
diff --git a/phosphor-power-supply/psu_manager.hpp b/phosphor-power-supply/psu_manager.hpp
index 13da13c..ca4fb45 100644
--- a/phosphor-power-supply/psu_manager.hpp
+++ b/phosphor-power-supply/psu_manager.hpp
@@ -107,6 +107,7 @@
         onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
         clearFaults();
         updateInventory();
+        setPowerConfigGPIO();
     }
 
     /**
@@ -275,6 +276,12 @@
                            std::map<std::string, std::string>& additionalData);
 
     /**
+     * @brief Set the power-config-full-load GPIO depending on the EM full load
+     *        property value.
+     */
+    void setPowerConfigGPIO();
+
+    /**
      * @brief Map of supported PSU configurations that include the model name
      * and their properties.
      */
@@ -284,6 +291,11 @@
      * @brief The vector for power supplies.
      */
     std::vector<std::unique_ptr<PowerSupply>> psus;
+
+    /**
+     * @brief The libgpiod object for setting the power supply config
+     */
+    std::unique_ptr<GPIOInterfaceBase> powerConfigGPIO = nullptr;
 };
 
 } // namespace phosphor::power::manager
diff --git a/phosphor-power-supply/util.cpp b/phosphor-power-supply/util.cpp
index 63719d3..0a7e20d 100644
--- a/phosphor-power-supply/util.cpp
+++ b/phosphor-power-supply/util.cpp
@@ -23,9 +23,8 @@
     }
     catch (const std::exception& e)
     {
-        phosphor::logging::log<phosphor::logging::level::ERR>(
-            fmt::format("Failed to find line: {}", e.what()).c_str());
-        throw;
+        throw std::runtime_error(std::string("Failed to find line: ") +
+                                 e.what());
     }
 }