summaryrefslogtreecommitdiff
path: root/meta-quanta/meta-gbs/recipes-phosphor/sensors/phosphor-hwmon/0002-lev-add-sensors-slow-readings.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-quanta/meta-gbs/recipes-phosphor/sensors/phosphor-hwmon/0002-lev-add-sensors-slow-readings.patch')
-rw-r--r--meta-quanta/meta-gbs/recipes-phosphor/sensors/phosphor-hwmon/0002-lev-add-sensors-slow-readings.patch295
1 files changed, 295 insertions, 0 deletions
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 000000000..0ab2f2048
--- /dev/null
+++ b/meta-quanta/meta-gbs/recipes-phosphor/sensors/phosphor-hwmon/0002-lev-add-sensors-slow-readings.patch
@@ -0,0 +1,295 @@
+From 8eafa1b0513dd2f5898182487b4524a485bf1e21 Mon Sep 17 00:00:00 2001
+From: Eddielu <Eddie.Lu@quantatw.com>
+Date: Mon, 27 Jul 2020 20:54:28 +0800
+Subject: [PATCH] Update add sensors slow readings patch.
+
+---
+ mainloop.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
+ mainloop.hpp | 3 +++
+ meson.build | 1 +
+ sensor.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------
+ sensor.hpp | 20 ++++++++++++++--
+ 5 files changed, 158 insertions(+), 14 deletions(-)
+
+diff --git a/mainloop.cpp b/mainloop.cpp
+index 4789a80..98d0658 100644
+--- a/mainloop.cpp
++++ b/mainloop.cpp
+@@ -34,6 +34,7 @@
+ #include <cassert>
+ #include <cstdlib>
+ #include <functional>
++#include <future>
+ #include <iostream>
+ #include <memory>
+ #include <phosphor-logging/elog-errors.hpp>
+@@ -299,7 +300,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<int64_t> asyncThread;
++
++ auto asyncIter = _timedoutMap.find(sensorSetKey);
++ if (asyncIter == _timedoutMap.end())
++ {
++ // If sensor 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 b3de022..6803c4b 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<int64_t>> _timedoutMap;
+
+ /**
+ * @brief Map of removed sensors
+diff --git a/meson.build b/meson.build
+index 66e6801..d6a92f8 100644
+--- a/meson.build
++++ b/meson.build
+@@ -84,6 +84,7 @@ libhwmon_all = static_library(
+ gpioplus,
+ phosphor_dbus_interfaces,
+ phosphor_logging,
++ threads,
+ ],
+ link_with: [
+ libaverage,
+diff --git a/sensor.cpp b/sensor.cpp
+index b1cb470..72b45f8 100644
+--- a/sensor.cpp
++++ b/sensor.cpp
+@@ -15,6 +15,7 @@
+ #include <cmath>
+ #include <cstring>
+ #include <filesystem>
++#include <future>
+ #include <phosphor-logging/elog-errors.hpp>
+ #include <thread>
+ #include <xyz/openbmc_project/Common/error.hpp>
+@@ -125,8 +126,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<int64_t>>& timedoutMap)
+ {
+ static constexpr bool deferSignals = true;
+
+@@ -153,12 +155,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<int64_t> asyncThread;
++
++ auto asyncIter = timedoutMap.find(_sensor);
++ if (asyncIter == timedoutMap.end())
++ {
++ // If sensor 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));
++ }
+ }
+ #ifdef UPDATE_FUNCTIONAL_ON_FAIL
+ catch (const std::system_error& e)
+diff --git a/sensor.hpp b/sensor.hpp
+index 369a252..41c0fe7 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,13 @@ 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<int64_t>>& timedoutMap);
+
+ /**
+ * @brief Add status interface and functional property for sensor
+--
+2.7.4
+