blob: 1c91c1ee36da85f703d5020f0aba96b29bf7c072 [file] [log] [blame]
Patrick Venture043d3232018-08-31 10:10:53 -07001#include "config.h"
2
3#include "sensor.hpp"
4
5#include "env.hpp"
Patrick Ventureb28f4322018-09-14 10:19:14 -07006#include "gpio_handle.hpp"
Patrick Venture043d3232018-08-31 10:10:53 -07007#include "hwmon.hpp"
8#include "sensorset.hpp"
9#include "sysfs.hpp"
10
Matt Spinler5e034af2020-06-24 15:21:53 -050011#include <fmt/format.h>
12
Brandon Kim86dcac82019-06-18 17:48:51 -070013#include <cassert>
William A. Kennington III2227bd52019-06-19 11:32:22 -070014#include <chrono>
James Feistee73f5b2018-08-01 16:31:42 -070015#include <cmath>
Matthew Barthcb3daaf2018-05-07 15:03:16 -050016#include <cstring>
Patrick Venture9e997b42019-03-08 13:42:10 -080017#include <filesystem>
Matthew Barth35819382018-04-18 14:53:01 -050018#include <phosphor-logging/elog-errors.hpp>
Patrick Ventureb28f4322018-09-14 10:19:14 -070019#include <thread>
20#include <xyz/openbmc_project/Common/error.hpp>
Matthew Barth35819382018-04-18 14:53:01 -050021#include <xyz/openbmc_project/Sensor/Device/error.hpp>
22
Matthew Barth35819382018-04-18 14:53:01 -050023namespace sensor
24{
25
Matthew Barthcb3daaf2018-05-07 15:03:16 -050026using namespace phosphor::logging;
Patrick Ventureb28f4322018-09-14 10:19:14 -070027using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Matthew Barthcb3daaf2018-05-07 15:03:16 -050028
James Feistee73f5b2018-08-01 16:31:42 -070029// todo: this can be deleted once we move to double
30// helper class to set the scale on the value iface only when it's available
31template <typename T>
32void setScale(T& iface, int64_t value, double)
33{
34}
35template <typename T>
36void setScale(T& iface, int64_t value, int64_t)
37{
38 iface->scale(value);
39}
40
41// todo: this can be simplified once we move to the double interface
Matthew Barth2e41b132018-05-07 14:15:45 -050042Sensor::Sensor(const SensorSet::key_type& sensor,
Patrick Venture2864b062018-12-19 08:13:41 -080043 const hwmonio::HwmonIOInterface* ioAccess,
44 const std::string& devPath) :
Patrick Venture12659aa2018-12-19 13:58:43 -080045 _sensor(sensor),
Brandon Kim86dcac82019-06-18 17:48:51 -070046 _ioAccess(ioAccess), _devPath(devPath), _scale(0), _hasFaultFile(false)
Matthew Barth9c431062018-05-07 13:55:29 -050047{
Patrick Ventureb28f4322018-09-14 10:19:14 -070048 auto chip = env::getEnv("GPIOCHIP", sensor);
49 auto access = env::getEnv("GPIO", sensor);
50 if (!access.empty() && !chip.empty())
51 {
Patrick Venture12659aa2018-12-19 13:58:43 -080052 _handle = gpio::BuildGpioHandle(chip, access);
Patrick Ventureb28f4322018-09-14 10:19:14 -070053
Patrick Venture12659aa2018-12-19 13:58:43 -080054 if (!_handle)
Patrick Ventureb28f4322018-09-14 10:19:14 -070055 {
56 log<level::ERR>("Unable to set up gpio locking");
57 elog<InternalFailure>();
58 }
59 }
60
Matthew Barthac473092018-05-07 14:41:46 -050061 auto gain = env::getEnv("GAIN", sensor);
62 if (!gain.empty())
63 {
Patrick Venture12659aa2018-12-19 13:58:43 -080064 _sensorAdjusts.gain = std::stod(gain);
Matthew Barthac473092018-05-07 14:41:46 -050065 }
66
67 auto offset = env::getEnv("OFFSET", sensor);
68 if (!offset.empty())
69 {
Patrick Venture12659aa2018-12-19 13:58:43 -080070 _sensorAdjusts.offset = std::stoi(offset);
Matthew Barthac473092018-05-07 14:41:46 -050071 }
72 auto senRmRCs = env::getEnv("REMOVERCS", sensor);
73 // Add sensor removal return codes defined per sensor
74 addRemoveRCs(senRmRCs);
Matthew Barth9c431062018-05-07 13:55:29 -050075}
76
Matthew Barthcb3daaf2018-05-07 15:03:16 -050077void Sensor::addRemoveRCs(const std::string& rcList)
78{
79 if (rcList.empty())
80 {
81 return;
82 }
83
84 // Convert to a char* for strtok
Patrick Venture043d3232018-08-31 10:10:53 -070085 std::vector<char> rmRCs(rcList.c_str(), rcList.c_str() + rcList.size() + 1);
Matthew Barthcb3daaf2018-05-07 15:03:16 -050086 auto rmRC = std::strtok(&rmRCs[0], ", ");
87 while (rmRC != nullptr)
88 {
89 try
90 {
Patrick Venture12659aa2018-12-19 13:58:43 -080091 _sensorAdjusts.rmRCs.insert(std::stoi(rmRC));
Matthew Barthcb3daaf2018-05-07 15:03:16 -050092 }
93 catch (const std::logic_error& le)
94 {
95 // Unable to convert to int, continue to next token
Patrick Venture12659aa2018-12-19 13:58:43 -080096 std::string name = _sensor.first + "_" + _sensor.second;
Matthew Barthcb3daaf2018-05-07 15:03:16 -050097 log<level::INFO>("Unable to convert sensor removal return code",
98 entry("SENSOR=%s", name.c_str()),
99 entry("RC=%s", rmRC),
100 entry("EXCEPTION=%s", le.what()));
101 }
102 rmRC = std::strtok(nullptr, ", ");
103 }
104}
105
James Feistee73f5b2018-08-01 16:31:42 -0700106SensorValueType Sensor::adjustValue(SensorValueType value)
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500107{
108// Because read doesn't have an out pointer to store errors.
109// let's assume negative values are errors if they have this
110// set.
111#ifdef NEGATIVE_ERRNO_ON_FAIL
112 if (value < 0)
113 {
114 return value;
115 }
116#endif
117
118 // Adjust based on gain and offset
Patrick Venture12659aa2018-12-19 13:58:43 -0800119 value = static_cast<decltype(value)>(static_cast<double>(value) *
120 _sensorAdjusts.gain +
121 _sensorAdjusts.offset);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500122
James Feistee73f5b2018-08-01 16:31:42 -0700123 if constexpr (std::is_same<SensorValueType, double>::value)
124 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800125 value *= std::pow(10, _scale);
James Feistee73f5b2018-08-01 16:31:42 -0700126 }
127
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500128 return value;
129}
130
Patrick Venture043d3232018-08-31 10:10:53 -0700131std::shared_ptr<ValueObject> Sensor::addValue(const RetryIO& retryIO,
132 ObjectInfo& info)
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500133{
134 static constexpr bool deferSignals = true;
135
136 // Get the initial value for the value interface.
137 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
Patrick Venture62067232019-06-19 17:39:33 -0700138 auto& obj = std::get<InterfaceMap>(info);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500139 auto& objPath = std::get<std::string>(info);
140
James Feistee73f5b2018-08-01 16:31:42 -0700141 SensorValueType val = 0;
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500142
Brandon Kim86dcac82019-06-18 17:48:51 -0700143 auto& statusIface = std::any_cast<std::shared_ptr<StatusObject>&>(
144 obj[InterfaceType::STATUS]);
145 // As long as addStatus is called before addValue, statusIface
146 // should never be nullptr
147 assert(statusIface);
148
149 // Only read the input value if the status is functional
150 if (statusIface->functional())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500151 {
Brandon Kim79205b22019-06-20 12:18:24 -0700152#ifdef UPDATE_FUNCTIONAL_ON_FAIL
153 try
154#endif
155 {
156 // RAII object for GPIO unlock / lock
William A. Kennington III2227bd52019-06-19 11:32:22 -0700157 auto locker = gpioUnlock(getGpio());
Patrick Ventureb28f4322018-09-14 10:19:14 -0700158
Brandon Kim79205b22019-06-20 12:18:24 -0700159 // Retry for up to a second if device is busy
160 // or has a transient error.
161 val =
162 _ioAccess->read(_sensor.first, _sensor.second,
163 hwmon::entry::cinput, std::get<size_t>(retryIO),
164 std::get<std::chrono::milliseconds>(retryIO));
Patrick Ventureb28f4322018-09-14 10:19:14 -0700165
Brandon Kim79205b22019-06-20 12:18:24 -0700166 val = adjustValue(val);
167 }
168#ifdef UPDATE_FUNCTIONAL_ON_FAIL
169 catch (const std::system_error& e)
170 {
171 // Catch the exception here and update the functional property.
172 // By catching the exception, it will not propagate it up the stack
173 // and thus the code will skip the "Remove RCs" check in
174 // MainLoop::getObject and will not exit on failure.
175 statusIface->functional(false);
176 }
177#endif
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500178 }
179
Patrick Venture043d3232018-08-31 10:10:53 -0700180 auto iface =
181 std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500182 iface->value(val);
183
184 hwmon::Attributes attrs;
Patrick Venture12659aa2018-12-19 13:58:43 -0800185 if (hwmon::getAttributes(_sensor.first, attrs))
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500186 {
187 iface->unit(hwmon::getUnit(attrs));
James Feistee73f5b2018-08-01 16:31:42 -0700188
189 setScale(iface, hwmon::getScale(attrs), val);
190
Patrick Venture12659aa2018-12-19 13:58:43 -0800191 _scale = hwmon::getScale(attrs);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500192 }
193
Patrick Venture12659aa2018-12-19 13:58:43 -0800194 auto maxValue = env::getEnv("MAXVALUE", _sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700195 if (!maxValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500196 {
197 iface->maxValue(std::stoll(maxValue));
198 }
Patrick Venture12659aa2018-12-19 13:58:43 -0800199 auto minValue = env::getEnv("MINVALUE", _sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700200 if (!minValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500201 {
202 iface->minValue(std::stoll(minValue));
203 }
204
205 obj[InterfaceType::VALUE] = iface;
206 return iface;
207}
208
Matthew Barth2e41b132018-05-07 14:15:45 -0500209std::shared_ptr<StatusObject> Sensor::addStatus(ObjectInfo& info)
Matthew Barth35819382018-04-18 14:53:01 -0500210{
Patrick Venture9e997b42019-03-08 13:42:10 -0800211 namespace fs = std::filesystem;
Matthew Barth35819382018-04-18 14:53:01 -0500212
213 std::shared_ptr<StatusObject> iface = nullptr;
Matthew Barth35819382018-04-18 14:53:01 -0500214 auto& objPath = std::get<std::string>(info);
Patrick Venture62067232019-06-19 17:39:33 -0700215 auto& obj = std::get<InterfaceMap>(info);
Matthew Barth35819382018-04-18 14:53:01 -0500216
217 // Check if fault sysfs file exists
Patrick Venture12659aa2018-12-19 13:58:43 -0800218 std::string faultName = _sensor.first;
219 std::string faultID = _sensor.second;
Matthew Barth35819382018-04-18 14:53:01 -0500220 std::string entry = hwmon::entry::fault;
221
Brandon Kim86dcac82019-06-18 17:48:51 -0700222 bool functional = true;
Patrick Venture043d3232018-08-31 10:10:53 -0700223 auto sysfsFullPath =
Patrick Venture12659aa2018-12-19 13:58:43 -0800224 sysfs::make_sysfs_path(_ioAccess->path(), faultName, faultID, entry);
Matthew Barth35819382018-04-18 14:53:01 -0500225 if (fs::exists(sysfsFullPath))
226 {
Brandon Kim86dcac82019-06-18 17:48:51 -0700227 _hasFaultFile = true;
Matthew Barth35819382018-04-18 14:53:01 -0500228 try
229 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800230 uint32_t fault = _ioAccess->read(faultName, faultID, entry,
231 hwmonio::retries, hwmonio::delay);
Matthew Barth35819382018-04-18 14:53:01 -0500232 if (fault != 0)
233 {
234 functional = false;
235 }
236 }
237 catch (const std::system_error& e)
238 {
Patrick Venture043d3232018-08-31 10:10:53 -0700239 using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::
240 Error;
241 using metadata = xyz::openbmc_project::Sensor::Device::ReadFailure;
Matthew Barth35819382018-04-18 14:53:01 -0500242
Patrick Venture12659aa2018-12-19 13:58:43 -0800243 report<ReadFailure>(
244 metadata::CALLOUT_ERRNO(e.code().value()),
245 metadata::CALLOUT_DEVICE_PATH(_devPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500246
Patrick Venture043d3232018-08-31 10:10:53 -0700247 log<level::INFO>(
Matt Spinler5e034af2020-06-24 15:21:53 -0500248 fmt::format("Failing sysfs file: {}", sysfsFullPath).c_str());
Matthew Barth35819382018-04-18 14:53:01 -0500249 }
Matthew Barth35819382018-04-18 14:53:01 -0500250 }
251
Brandon Kim86dcac82019-06-18 17:48:51 -0700252 static constexpr bool deferSignals = true;
253 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
254
255 iface = std::make_shared<StatusObject>(bus, objPath.c_str(), deferSignals);
256 // Set functional property
257 iface->functional(functional);
258
259 obj[InterfaceType::STATUS] = iface;
260
Matthew Barth35819382018-04-18 14:53:01 -0500261 return iface;
262}
263
William A. Kennington III2227bd52019-06-19 11:32:22 -0700264void gpioLock(const gpioplus::HandleInterface*&& handle)
Brandon Kimdb76d492019-06-17 11:53:04 -0700265{
William A. Kennington III2227bd52019-06-19 11:32:22 -0700266 handle->setValues({0});
Brandon Kimdb76d492019-06-17 11:53:04 -0700267}
268
William A. Kennington III2227bd52019-06-19 11:32:22 -0700269std::optional<GpioLocker> gpioUnlock(const gpioplus::HandleInterface* handle)
Brandon Kimdb76d492019-06-17 11:53:04 -0700270{
William A. Kennington III2227bd52019-06-19 11:32:22 -0700271 if (handle == nullptr)
Patrick Ventureb28f4322018-09-14 10:19:14 -0700272 {
William A. Kennington III2227bd52019-06-19 11:32:22 -0700273 return std::nullopt;
Patrick Ventureb28f4322018-09-14 10:19:14 -0700274 }
Patrick Ventureb28f4322018-09-14 10:19:14 -0700275
William A. Kennington III2227bd52019-06-19 11:32:22 -0700276 handle->setValues({1});
277 // Default pause needed to guarantee sensors are ready
278 std::this_thread::sleep_for(std::chrono::milliseconds(500));
279 return GpioLocker(std::move(handle));
Patrick Ventureb28f4322018-09-14 10:19:14 -0700280}
281
Matthew Barth35819382018-04-18 14:53:01 -0500282} // namespace sensor