meta-quanta: gbs: add hwmon sensors

Define the configuration files of the related sensors
and test pass

0001-lev-add-poweron-monitor-feature.patch
In-Review: https://gerrit.openbmc-project.xyz/c/openbmc/phosphor-hwmon/+/28181

0002-lev-add-sensors-slow-readings.patch
In-Review: https://gerrit.openbmc-project.xyz/c/openbmc/phosphor-hwmon/+/24337

(From meta-quanta rev: a66f2b941cede5fc15fe0d6d56ca2ac9352fdf77)

Signed-off-by: George Hung <george.hung@quantatw.com>
Change-Id: If7f767cbd952cde593e03d30c45572a21cc7c960
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
diff --git a/meta-quanta/meta-gbs/recipes-phosphor/sensors/phosphor-hwmon/0002-lev-add-sensors-slow-readings.patch b/meta-quanta/meta-gbs/recipes-phosphor/sensors/phosphor-hwmon/0002-lev-add-sensors-slow-readings.patch
new file mode 100644
index 0000000..0a2efd8
--- /dev/null
+++ b/meta-quanta/meta-gbs/recipes-phosphor/sensors/phosphor-hwmon/0002-lev-add-sensors-slow-readings.patch
@@ -0,0 +1,284 @@
+From 61b91122b72d7a3a5c93b80b6fb6d3ac892619dc Mon Sep 17 00:00:00 2001
+From: Eddielu <Eddie.Lu@quantatw.com>
+Date: Mon, 1 Jun 2020 14:18:33 +0800
+Subject: [PATCH] add sensors slow readings
+
+---
+ mainloop.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
+ mainloop.hpp |  3 +++
+ sensor.cpp   | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------
+ sensor.hpp   | 21 +++++++++++++++--
+ 4 files changed, 158 insertions(+), 15 deletions(-)
+
+diff --git a/mainloop.cpp b/mainloop.cpp
+index 1769e94..5094343 100644
+--- a/mainloop.cpp
++++ b/mainloop.cpp
+@@ -32,6 +32,7 @@
+ #include <cassert>
+ #include <cstdlib>
+ #include <functional>
++#include <future>
+ #include <iostream>
+ #include <memory>
+ #include <phosphor-logging/elog-errors.hpp>
+@@ -296,7 +297,7 @@ std::optional<ObjectStateData>
+     {
+         // Add status interface based on _fault file being present
+         sensorObj->addStatus(info);
+-        valueInterface = sensorObj->addValue(retryIO, info);
++        valueInterface = sensorObj->addValue(retryIO, info, _timedoutMap);
+     }
+     catch (const std::system_error& e)
+     {
+@@ -542,10 +543,74 @@ void MainLoop::read()
+                 // RAII object for GPIO unlock / lock
+                 auto locker = sensor::gpioUnlock(sensor->getGpio());
+ 
+-                // Retry for up to a second if device is busy
+-                // or has a transient error.
+-                value = _ioAccess->read(sensorSysfsType, sensorSysfsNum, input,
++                // For sensors with attribute ASYNC_READ_TIMEOUT,
++                // spawn a thread with timeout
++                auto asyncRead =
++                    env::getEnv("ASYNC_READ_TIMEOUT", sensorSetKey);
++                if (!asyncRead.empty())
++                {
++                    // Default async read timeout
++                    std::chrono::milliseconds asyncReadTimeout{
++                        std::stoi(asyncRead)};
++                    bool valueIsValid = false;
++                    std::future<SensorValueType> asyncThread;
++
++                    auto asyncIter = _timedoutMap.find(sensorSetKey);
++                    if (asyncIter == _timedoutMap.end())
++                    {
++                        // If sesnor not found in timedoutMap, spawn an async
++                        // thread
++                        asyncThread = std::async(
++                            std::launch::async,
++                            &hwmonio::HwmonIOInterface::read, _ioAccess,
++                            sensorSysfsType, sensorSysfsNum, input,
++                            hwmonio::retries, hwmonio::delay);
++                        valueIsValid = true;
++                    }
++                    else
++                    {
++                        // If we already have the async thread in the
++                        // timedoutMap, it means this sensor has already timed
++                        // out in the previous reads. No need to wait on
++                        // subsequent reads
++                        asyncReadTimeout = std::chrono::seconds(0);
++                        asyncThread = std::move(asyncIter->second);
++                    }
++
++                    std::future_status status =
++                        asyncThread.wait_for(asyncReadTimeout);
++                    switch (status)
++                    {
++                        // Read has finished
++                        case std::future_status::ready:
++                            // Read has finished
++                            if (valueIsValid)
++                            {
++                                value = asyncThread.get();
++                                break;
++                                // Good sensor reads should skip the code below
++                            }
++                            // Async read thread has completed, erase from
++                            // timedoutMap to allow retry then throw
++                            _timedoutMap.erase(sensorSetKey);
++                            throw sensor::AsyncSensorReadTimeOut();
++                        default:
++                            // Read timed out so add the thread to the
++                            // timedoutMap (if the entry already exists,
++                            // operator[] updates it)
++                            _timedoutMap[sensorSetKey] = std::move(asyncThread);
++                            throw sensor::AsyncSensorReadTimeOut();
++                    }
++                }
++                else
++                {
++                    // Retry for up to a second if device is busy
++                    // or has a transient error.
++                    value =
++                        _ioAccess->read(sensorSysfsType, sensorSysfsNum, input,
+                                         hwmonio::retries, hwmonio::delay);
++                }
++
+                 // Set functional property to true if we could read sensor
+                 statusIface->functional(true);
+ 
+diff --git a/mainloop.hpp b/mainloop.hpp
+index 6c5b8e0..cfe34d5 100644
+--- a/mainloop.hpp
++++ b/mainloop.hpp
+@@ -9,6 +9,7 @@
+ #include "types.hpp"
+ 
+ #include <any>
++#include <future>
+ #include <memory>
+ #include <optional>
+ #include <sdbusplus/server.hpp>
+@@ -116,6 +117,8 @@ class MainLoop
+     /** @brief Store the specifications of sensor objects */
+     std::map<SensorSet::key_type, std::unique_ptr<sensor::Sensor>>
+         _sensorObjects;
++    /** @brief Store the async futures of timed out sensor objects */
++    std::map<SensorSet::key_type, std::future<SensorValueType>> _timedoutMap;
+ 
+     /**
+      * @brief Map of removed sensors
+diff --git a/sensor.cpp b/sensor.cpp
+index 93bbb03..7b681e1 100644
+--- a/sensor.cpp
++++ b/sensor.cpp
+@@ -13,6 +13,7 @@
+ #include <cmath>
+ #include <cstring>
+ #include <filesystem>
++#include <future>
+ #include <phosphor-logging/elog-errors.hpp>
+ #include <thread>
+ #include <xyz/openbmc_project/Common/error.hpp>
+@@ -135,8 +136,9 @@ SensorValueType Sensor::adjustValue(SensorValueType value)
+     return value;
+ }
+ 
+-std::shared_ptr<ValueObject> Sensor::addValue(const RetryIO& retryIO,
+-                                              ObjectInfo& info)
++std::shared_ptr<ValueObject> Sensor::addValue(
++    const RetryIO& retryIO, ObjectInfo& info,
++    std::map<SensorSet::key_type, std::future<SensorValueType>>& timedoutMap)
+ {
+     static constexpr bool deferSignals = true;
+ 
+@@ -163,13 +165,69 @@ std::shared_ptr<ValueObject> Sensor::addValue(const RetryIO& retryIO,
+             // RAII object for GPIO unlock / lock
+             auto locker = gpioUnlock(getGpio());
+ 
+-            // Retry for up to a second if device is busy
+-            // or has a transient error.
+-            val =
+-                _ioAccess->read(_sensor.first, _sensor.second,
+-                                hwmon::entry::cinput, std::get<size_t>(retryIO),
+-                                std::get<std::chrono::milliseconds>(retryIO));
+-
++            // For sensors with attribute ASYNC_READ_TIMEOUT,
++            // spawn a thread with timeout
++            auto asyncRead = env::getEnv("ASYNC_READ_TIMEOUT", _sensor);
++            if (!asyncRead.empty())
++            {
++                // Default async read timeout
++                std::chrono::milliseconds asyncReadTimeout{
++                    std::stoi(asyncRead)};
++                bool valueIsValid = false;
++                std::future<SensorValueType> asyncThread;
++
++                auto asyncIter = timedoutMap.find(_sensor);
++                if (asyncIter == timedoutMap.end())
++                {
++                    // If sesnor not found in timedoutMap, spawn an async thread
++                    asyncThread = std::async(
++                        std::launch::async, &hwmonio::HwmonIOInterface::read,
++                        _ioAccess, _sensor.first, _sensor.second,
++                        hwmon::entry::cinput, std::get<size_t>(retryIO),
++                        std::get<std::chrono::milliseconds>(retryIO));
++                    valueIsValid = true;
++                }
++                else
++                {
++                    // If we already have the async thread in the timedoutMap,
++                    // it means this sensor has already timed out in the
++                    // previous reads. No need to wait on subsequent reads
++                    asyncReadTimeout = std::chrono::seconds(0);
++                    asyncThread = std::move(asyncIter->second);
++                }
++
++                std::future_status status =
++                    asyncThread.wait_for(asyncReadTimeout);
++                switch (status)
++                {
++                    case std::future_status::ready:
++                        // Read has finished
++                        if (valueIsValid)
++                        {
++                            val = asyncThread.get();
++                            break;
++                            // Good sensor reads should skip the code below
++                        }
++                        // Async read thread has completed, erase from
++                        // timedoutMap to allow retry then throw
++                        timedoutMap.erase(_sensor);
++                        throw AsyncSensorReadTimeOut();
++                    default:
++                        // Read timed out so add the thread to the timedoutMap
++                        // (if the entry already exists, operator[] updates it)
++                        timedoutMap[_sensor] = std::move(asyncThread);
++                        throw AsyncSensorReadTimeOut();
++                }
++            }
++            else
++            {
++                // Retry for up to a second if device is busy
++                // or has a transient error.
++                val = _ioAccess->read(
++                    _sensor.first, _sensor.second, hwmon::entry::cinput,
++                    std::get<size_t>(retryIO),
++                    std::get<std::chrono::milliseconds>(retryIO));
++            }
+             val = adjustValue(val);
+         }
+ #ifdef UPDATE_FUNCTIONAL_ON_FAIL
+diff --git a/sensor.hpp b/sensor.hpp
+index 369a252..d1d6730 100644
+--- a/sensor.hpp
++++ b/sensor.hpp
+@@ -4,6 +4,8 @@
+ #include "sensorset.hpp"
+ #include "types.hpp"
+ 
++#include <cerrno>
++#include <future>
+ #include <gpioplus/handle.hpp>
+ #include <memory>
+ #include <optional>
+@@ -20,6 +22,17 @@ struct valueAdjust
+     std::unordered_set<int> rmRCs;
+ };
+ 
++/** @brief Custom exception for async sensor reading timeout
++ */
++struct AsyncSensorReadTimeOut : public std::system_error
++{
++    AsyncSensorReadTimeOut() :
++        system_error(std::error_code(ETIMEDOUT, std::system_category()),
++                     "Async sensor read timed out")
++    {
++    }
++};
++
+ /** @class Sensor
+  *  @brief Sensor object based on a SensorSet container's key type
+  *  @details Sensor object to create and modify an associated device's sensor
+@@ -87,10 +100,14 @@ class Sensor
+      *                      (number of and delay between)
+      * @param[in] info - Sensor object information
+      *
++     * @param[in] timedoutMap - Map to track timed out threads
++     *
+      * @return - Shared pointer to the value object
+      */
+-    std::shared_ptr<ValueObject> addValue(const RetryIO& retryIO,
+-                                          ObjectInfo& info);
++    std::shared_ptr<ValueObject>
++        addValue(const RetryIO& retryIO, ObjectInfo& info,
++                 std::map<SensorSet::key_type, std::future<SensorValueType>>&
++                     timedoutMap);
+ 
+     /**
+      * @brief Add status interface and functional property for sensor
+-- 
+2.7.4
+