blob: 145ba6c81be75feb802a219d24cefee45251d88c [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
Brandon Kim86dcac82019-06-18 17:48:51 -070011#include <cassert>
William A. Kennington III2227bd52019-06-19 11:32:22 -070012#include <chrono>
James Feistee73f5b2018-08-01 16:31:42 -070013#include <cmath>
Matthew Barthcb3daaf2018-05-07 15:03:16 -050014#include <cstring>
Patrick Venture9e997b42019-03-08 13:42:10 -080015#include <filesystem>
Matthew Barth35819382018-04-18 14:53:01 -050016#include <phosphor-logging/elog-errors.hpp>
Patrick Ventureb28f4322018-09-14 10:19:14 -070017#include <thread>
18#include <xyz/openbmc_project/Common/error.hpp>
Matthew Barth35819382018-04-18 14:53:01 -050019#include <xyz/openbmc_project/Sensor/Device/error.hpp>
20
Matthew Barth35819382018-04-18 14:53:01 -050021namespace sensor
22{
23
Matthew Barthcb3daaf2018-05-07 15:03:16 -050024using namespace phosphor::logging;
Patrick Ventureb28f4322018-09-14 10:19:14 -070025using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Matthew Barthcb3daaf2018-05-07 15:03:16 -050026
James Feistee73f5b2018-08-01 16:31:42 -070027// todo: this can be deleted once we move to double
28// helper class to set the scale on the value iface only when it's available
29template <typename T>
30void setScale(T& iface, int64_t value, double)
31{
32}
33template <typename T>
34void setScale(T& iface, int64_t value, int64_t)
35{
36 iface->scale(value);
37}
38
39// todo: this can be simplified once we move to the double interface
Matthew Barth2e41b132018-05-07 14:15:45 -050040Sensor::Sensor(const SensorSet::key_type& sensor,
Patrick Venture2864b062018-12-19 08:13:41 -080041 const hwmonio::HwmonIOInterface* ioAccess,
42 const std::string& devPath) :
Patrick Venture12659aa2018-12-19 13:58:43 -080043 _sensor(sensor),
Brandon Kim86dcac82019-06-18 17:48:51 -070044 _ioAccess(ioAccess), _devPath(devPath), _scale(0), _hasFaultFile(false)
Matthew Barth9c431062018-05-07 13:55:29 -050045{
Patrick Ventureb28f4322018-09-14 10:19:14 -070046 auto chip = env::getEnv("GPIOCHIP", sensor);
47 auto access = env::getEnv("GPIO", sensor);
48 if (!access.empty() && !chip.empty())
49 {
Patrick Venture12659aa2018-12-19 13:58:43 -080050 _handle = gpio::BuildGpioHandle(chip, access);
Patrick Ventureb28f4322018-09-14 10:19:14 -070051
Patrick Venture12659aa2018-12-19 13:58:43 -080052 if (!_handle)
Patrick Ventureb28f4322018-09-14 10:19:14 -070053 {
54 log<level::ERR>("Unable to set up gpio locking");
55 elog<InternalFailure>();
56 }
57 }
58
Matthew Barthac473092018-05-07 14:41:46 -050059 auto gain = env::getEnv("GAIN", sensor);
60 if (!gain.empty())
61 {
Patrick Venture12659aa2018-12-19 13:58:43 -080062 _sensorAdjusts.gain = std::stod(gain);
Matthew Barthac473092018-05-07 14:41:46 -050063 }
64
65 auto offset = env::getEnv("OFFSET", sensor);
66 if (!offset.empty())
67 {
Patrick Venture12659aa2018-12-19 13:58:43 -080068 _sensorAdjusts.offset = std::stoi(offset);
Matthew Barthac473092018-05-07 14:41:46 -050069 }
70 auto senRmRCs = env::getEnv("REMOVERCS", sensor);
71 // Add sensor removal return codes defined per sensor
72 addRemoveRCs(senRmRCs);
Matthew Barth9c431062018-05-07 13:55:29 -050073}
74
Matthew Barthcb3daaf2018-05-07 15:03:16 -050075void Sensor::addRemoveRCs(const std::string& rcList)
76{
77 if (rcList.empty())
78 {
79 return;
80 }
81
82 // Convert to a char* for strtok
Patrick Venture043d3232018-08-31 10:10:53 -070083 std::vector<char> rmRCs(rcList.c_str(), rcList.c_str() + rcList.size() + 1);
Matthew Barthcb3daaf2018-05-07 15:03:16 -050084 auto rmRC = std::strtok(&rmRCs[0], ", ");
85 while (rmRC != nullptr)
86 {
87 try
88 {
Patrick Venture12659aa2018-12-19 13:58:43 -080089 _sensorAdjusts.rmRCs.insert(std::stoi(rmRC));
Matthew Barthcb3daaf2018-05-07 15:03:16 -050090 }
91 catch (const std::logic_error& le)
92 {
93 // Unable to convert to int, continue to next token
Patrick Venture12659aa2018-12-19 13:58:43 -080094 std::string name = _sensor.first + "_" + _sensor.second;
Matthew Barthcb3daaf2018-05-07 15:03:16 -050095 log<level::INFO>("Unable to convert sensor removal return code",
96 entry("SENSOR=%s", name.c_str()),
97 entry("RC=%s", rmRC),
98 entry("EXCEPTION=%s", le.what()));
99 }
100 rmRC = std::strtok(nullptr, ", ");
101 }
102}
103
James Feistee73f5b2018-08-01 16:31:42 -0700104SensorValueType Sensor::adjustValue(SensorValueType value)
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500105{
106// Because read doesn't have an out pointer to store errors.
107// let's assume negative values are errors if they have this
108// set.
109#ifdef NEGATIVE_ERRNO_ON_FAIL
110 if (value < 0)
111 {
112 return value;
113 }
114#endif
115
116 // Adjust based on gain and offset
Patrick Venture12659aa2018-12-19 13:58:43 -0800117 value = static_cast<decltype(value)>(static_cast<double>(value) *
118 _sensorAdjusts.gain +
119 _sensorAdjusts.offset);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500120
James Feistee73f5b2018-08-01 16:31:42 -0700121 if constexpr (std::is_same<SensorValueType, double>::value)
122 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800123 value *= std::pow(10, _scale);
James Feistee73f5b2018-08-01 16:31:42 -0700124 }
125
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500126 return value;
127}
128
Patrick Venture043d3232018-08-31 10:10:53 -0700129std::shared_ptr<ValueObject> Sensor::addValue(const RetryIO& retryIO,
130 ObjectInfo& info)
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500131{
132 static constexpr bool deferSignals = true;
133
134 // Get the initial value for the value interface.
135 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
Patrick Venture62067232019-06-19 17:39:33 -0700136 auto& obj = std::get<InterfaceMap>(info);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500137 auto& objPath = std::get<std::string>(info);
138
James Feistee73f5b2018-08-01 16:31:42 -0700139 SensorValueType val = 0;
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500140
Brandon Kim86dcac82019-06-18 17:48:51 -0700141 auto& statusIface = std::any_cast<std::shared_ptr<StatusObject>&>(
142 obj[InterfaceType::STATUS]);
143 // As long as addStatus is called before addValue, statusIface
144 // should never be nullptr
145 assert(statusIface);
146
147 // Only read the input value if the status is functional
148 if (statusIface->functional())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500149 {
Brandon Kim79205b22019-06-20 12:18:24 -0700150#ifdef UPDATE_FUNCTIONAL_ON_FAIL
151 try
152#endif
153 {
154 // RAII object for GPIO unlock / lock
William A. Kennington III2227bd52019-06-19 11:32:22 -0700155 auto locker = gpioUnlock(getGpio());
Patrick Ventureb28f4322018-09-14 10:19:14 -0700156
Brandon Kim79205b22019-06-20 12:18:24 -0700157 // Retry for up to a second if device is busy
158 // or has a transient error.
159 val =
160 _ioAccess->read(_sensor.first, _sensor.second,
161 hwmon::entry::cinput, std::get<size_t>(retryIO),
162 std::get<std::chrono::milliseconds>(retryIO));
Patrick Ventureb28f4322018-09-14 10:19:14 -0700163
Brandon Kim79205b22019-06-20 12:18:24 -0700164 val = adjustValue(val);
165 }
166#ifdef UPDATE_FUNCTIONAL_ON_FAIL
167 catch (const std::system_error& e)
168 {
169 // Catch the exception here and update the functional property.
170 // By catching the exception, it will not propagate it up the stack
171 // and thus the code will skip the "Remove RCs" check in
172 // MainLoop::getObject and will not exit on failure.
173 statusIface->functional(false);
174 }
175#endif
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500176 }
177
Patrick Venture043d3232018-08-31 10:10:53 -0700178 auto iface =
179 std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500180 iface->value(val);
181
182 hwmon::Attributes attrs;
Patrick Venture12659aa2018-12-19 13:58:43 -0800183 if (hwmon::getAttributes(_sensor.first, attrs))
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500184 {
185 iface->unit(hwmon::getUnit(attrs));
James Feistee73f5b2018-08-01 16:31:42 -0700186
187 setScale(iface, hwmon::getScale(attrs), val);
188
Patrick Venture12659aa2018-12-19 13:58:43 -0800189 _scale = hwmon::getScale(attrs);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500190 }
191
Patrick Venture12659aa2018-12-19 13:58:43 -0800192 auto maxValue = env::getEnv("MAXVALUE", _sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700193 if (!maxValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500194 {
195 iface->maxValue(std::stoll(maxValue));
196 }
Patrick Venture12659aa2018-12-19 13:58:43 -0800197 auto minValue = env::getEnv("MINVALUE", _sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700198 if (!minValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500199 {
200 iface->minValue(std::stoll(minValue));
201 }
202
203 obj[InterfaceType::VALUE] = iface;
204 return iface;
205}
206
Matthew Barth2e41b132018-05-07 14:15:45 -0500207std::shared_ptr<StatusObject> Sensor::addStatus(ObjectInfo& info)
Matthew Barth35819382018-04-18 14:53:01 -0500208{
Patrick Venture9e997b42019-03-08 13:42:10 -0800209 namespace fs = std::filesystem;
Matthew Barth35819382018-04-18 14:53:01 -0500210
211 std::shared_ptr<StatusObject> iface = nullptr;
Matthew Barth35819382018-04-18 14:53:01 -0500212 auto& objPath = std::get<std::string>(info);
Patrick Venture62067232019-06-19 17:39:33 -0700213 auto& obj = std::get<InterfaceMap>(info);
Matthew Barth35819382018-04-18 14:53:01 -0500214
215 // Check if fault sysfs file exists
Patrick Venture12659aa2018-12-19 13:58:43 -0800216 std::string faultName = _sensor.first;
217 std::string faultID = _sensor.second;
Matthew Barth35819382018-04-18 14:53:01 -0500218 std::string entry = hwmon::entry::fault;
219
Brandon Kim86dcac82019-06-18 17:48:51 -0700220 bool functional = true;
Patrick Venture043d3232018-08-31 10:10:53 -0700221 auto sysfsFullPath =
Patrick Venture12659aa2018-12-19 13:58:43 -0800222 sysfs::make_sysfs_path(_ioAccess->path(), faultName, faultID, entry);
Matthew Barth35819382018-04-18 14:53:01 -0500223 if (fs::exists(sysfsFullPath))
224 {
Brandon Kim86dcac82019-06-18 17:48:51 -0700225 _hasFaultFile = true;
Matthew Barth35819382018-04-18 14:53:01 -0500226 try
227 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800228 uint32_t fault = _ioAccess->read(faultName, faultID, entry,
229 hwmonio::retries, hwmonio::delay);
Matthew Barth35819382018-04-18 14:53:01 -0500230 if (fault != 0)
231 {
232 functional = false;
233 }
234 }
235 catch (const std::system_error& e)
236 {
Patrick Venture043d3232018-08-31 10:10:53 -0700237 using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::
238 Error;
239 using metadata = xyz::openbmc_project::Sensor::Device::ReadFailure;
Matthew Barth35819382018-04-18 14:53:01 -0500240
Patrick Venture12659aa2018-12-19 13:58:43 -0800241 report<ReadFailure>(
242 metadata::CALLOUT_ERRNO(e.code().value()),
243 metadata::CALLOUT_DEVICE_PATH(_devPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500244
Patrick Venture043d3232018-08-31 10:10:53 -0700245 log<level::INFO>(
246 "Logging failing sysfs file",
247 phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500248 }
Matthew Barth35819382018-04-18 14:53:01 -0500249 }
250
Brandon Kim86dcac82019-06-18 17:48:51 -0700251 static constexpr bool deferSignals = true;
252 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
253
254 iface = std::make_shared<StatusObject>(bus, objPath.c_str(), deferSignals);
255 // Set functional property
256 iface->functional(functional);
257
258 obj[InterfaceType::STATUS] = iface;
259
Matthew Barth35819382018-04-18 14:53:01 -0500260 return iface;
261}
262
William A. Kennington III2227bd52019-06-19 11:32:22 -0700263void gpioLock(const gpioplus::HandleInterface*&& handle)
Brandon Kimdb76d492019-06-17 11:53:04 -0700264{
William A. Kennington III2227bd52019-06-19 11:32:22 -0700265 handle->setValues({0});
Brandon Kimdb76d492019-06-17 11:53:04 -0700266}
267
William A. Kennington III2227bd52019-06-19 11:32:22 -0700268std::optional<GpioLocker> gpioUnlock(const gpioplus::HandleInterface* handle)
Brandon Kimdb76d492019-06-17 11:53:04 -0700269{
William A. Kennington III2227bd52019-06-19 11:32:22 -0700270 if (handle == nullptr)
Patrick Ventureb28f4322018-09-14 10:19:14 -0700271 {
William A. Kennington III2227bd52019-06-19 11:32:22 -0700272 return std::nullopt;
Patrick Ventureb28f4322018-09-14 10:19:14 -0700273 }
Patrick Ventureb28f4322018-09-14 10:19:14 -0700274
William A. Kennington III2227bd52019-06-19 11:32:22 -0700275 handle->setValues({1});
276 // Default pause needed to guarantee sensors are ready
277 std::this_thread::sleep_for(std::chrono::milliseconds(500));
278 return GpioLocker(std::move(handle));
Patrick Ventureb28f4322018-09-14 10:19:14 -0700279}
280
Matthew Barth35819382018-04-18 14:53:01 -0500281} // namespace sensor