blob: 6e5e841d596738a7e9a667cdbecd2e8d0672e584 [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>
James Feistee73f5b2018-08-01 16:31:42 -070012#include <cmath>
Matthew Barthcb3daaf2018-05-07 15:03:16 -050013#include <cstring>
Patrick Venture9e997b42019-03-08 13:42:10 -080014#include <filesystem>
Matthew Barth35819382018-04-18 14:53:01 -050015#include <phosphor-logging/elog-errors.hpp>
Patrick Ventureb28f4322018-09-14 10:19:14 -070016#include <thread>
17#include <xyz/openbmc_project/Common/error.hpp>
Matthew Barth35819382018-04-18 14:53:01 -050018#include <xyz/openbmc_project/Sensor/Device/error.hpp>
19
Matthew Barth35819382018-04-18 14:53:01 -050020namespace sensor
21{
22
Matthew Barthcb3daaf2018-05-07 15:03:16 -050023using namespace phosphor::logging;
Patrick Ventureb28f4322018-09-14 10:19:14 -070024using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Matthew Barthcb3daaf2018-05-07 15:03:16 -050025
James Feistee73f5b2018-08-01 16:31:42 -070026// todo: this can be deleted once we move to double
27// helper class to set the scale on the value iface only when it's available
28template <typename T>
29void setScale(T& iface, int64_t value, double)
30{
31}
32template <typename T>
33void setScale(T& iface, int64_t value, int64_t)
34{
35 iface->scale(value);
36}
37
38// todo: this can be simplified once we move to the double interface
Matthew Barth2e41b132018-05-07 14:15:45 -050039Sensor::Sensor(const SensorSet::key_type& sensor,
Patrick Venture2864b062018-12-19 08:13:41 -080040 const hwmonio::HwmonIOInterface* ioAccess,
41 const std::string& devPath) :
Patrick Venture12659aa2018-12-19 13:58:43 -080042 _sensor(sensor),
Brandon Kim86dcac82019-06-18 17:48:51 -070043 _ioAccess(ioAccess), _devPath(devPath), _scale(0), _hasFaultFile(false)
Matthew Barth9c431062018-05-07 13:55:29 -050044{
Patrick Ventureb28f4322018-09-14 10:19:14 -070045 auto chip = env::getEnv("GPIOCHIP", sensor);
46 auto access = env::getEnv("GPIO", sensor);
47 if (!access.empty() && !chip.empty())
48 {
Patrick Venture12659aa2018-12-19 13:58:43 -080049 _handle = gpio::BuildGpioHandle(chip, access);
Patrick Ventureb28f4322018-09-14 10:19:14 -070050
Patrick Venture12659aa2018-12-19 13:58:43 -080051 if (!_handle)
Patrick Ventureb28f4322018-09-14 10:19:14 -070052 {
53 log<level::ERR>("Unable to set up gpio locking");
54 elog<InternalFailure>();
55 }
56 }
57
Matthew Barthac473092018-05-07 14:41:46 -050058 auto gain = env::getEnv("GAIN", sensor);
59 if (!gain.empty())
60 {
Patrick Venture12659aa2018-12-19 13:58:43 -080061 _sensorAdjusts.gain = std::stod(gain);
Matthew Barthac473092018-05-07 14:41:46 -050062 }
63
64 auto offset = env::getEnv("OFFSET", sensor);
65 if (!offset.empty())
66 {
Patrick Venture12659aa2018-12-19 13:58:43 -080067 _sensorAdjusts.offset = std::stoi(offset);
Matthew Barthac473092018-05-07 14:41:46 -050068 }
69 auto senRmRCs = env::getEnv("REMOVERCS", sensor);
70 // Add sensor removal return codes defined per sensor
71 addRemoveRCs(senRmRCs);
Matthew Barth9c431062018-05-07 13:55:29 -050072}
73
Matthew Barthcb3daaf2018-05-07 15:03:16 -050074void Sensor::addRemoveRCs(const std::string& rcList)
75{
76 if (rcList.empty())
77 {
78 return;
79 }
80
81 // Convert to a char* for strtok
Patrick Venture043d3232018-08-31 10:10:53 -070082 std::vector<char> rmRCs(rcList.c_str(), rcList.c_str() + rcList.size() + 1);
Matthew Barthcb3daaf2018-05-07 15:03:16 -050083 auto rmRC = std::strtok(&rmRCs[0], ", ");
84 while (rmRC != nullptr)
85 {
86 try
87 {
Patrick Venture12659aa2018-12-19 13:58:43 -080088 _sensorAdjusts.rmRCs.insert(std::stoi(rmRC));
Matthew Barthcb3daaf2018-05-07 15:03:16 -050089 }
90 catch (const std::logic_error& le)
91 {
92 // Unable to convert to int, continue to next token
Patrick Venture12659aa2018-12-19 13:58:43 -080093 std::string name = _sensor.first + "_" + _sensor.second;
Matthew Barthcb3daaf2018-05-07 15:03:16 -050094 log<level::INFO>("Unable to convert sensor removal return code",
95 entry("SENSOR=%s", name.c_str()),
96 entry("RC=%s", rmRC),
97 entry("EXCEPTION=%s", le.what()));
98 }
99 rmRC = std::strtok(nullptr, ", ");
100 }
101}
102
James Feistee73f5b2018-08-01 16:31:42 -0700103SensorValueType Sensor::adjustValue(SensorValueType value)
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500104{
105// Because read doesn't have an out pointer to store errors.
106// let's assume negative values are errors if they have this
107// set.
108#ifdef NEGATIVE_ERRNO_ON_FAIL
109 if (value < 0)
110 {
111 return value;
112 }
113#endif
114
115 // Adjust based on gain and offset
Patrick Venture12659aa2018-12-19 13:58:43 -0800116 value = static_cast<decltype(value)>(static_cast<double>(value) *
117 _sensorAdjusts.gain +
118 _sensorAdjusts.offset);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500119
James Feistee73f5b2018-08-01 16:31:42 -0700120 if constexpr (std::is_same<SensorValueType, double>::value)
121 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800122 value *= std::pow(10, _scale);
James Feistee73f5b2018-08-01 16:31:42 -0700123 }
124
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500125 return value;
126}
127
Patrick Venture043d3232018-08-31 10:10:53 -0700128std::shared_ptr<ValueObject> Sensor::addValue(const RetryIO& retryIO,
129 ObjectInfo& info)
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500130{
131 static constexpr bool deferSignals = true;
132
133 // Get the initial value for the value interface.
134 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
Patrick Venture62067232019-06-19 17:39:33 -0700135 auto& obj = std::get<InterfaceMap>(info);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500136 auto& objPath = std::get<std::string>(info);
137
James Feistee73f5b2018-08-01 16:31:42 -0700138 SensorValueType val = 0;
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500139
Brandon Kim86dcac82019-06-18 17:48:51 -0700140 auto& statusIface = std::any_cast<std::shared_ptr<StatusObject>&>(
141 obj[InterfaceType::STATUS]);
142 // As long as addStatus is called before addValue, statusIface
143 // should never be nullptr
144 assert(statusIface);
145
146 // Only read the input value if the status is functional
147 if (statusIface->functional())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500148 {
Brandon Kim79205b22019-06-20 12:18:24 -0700149#ifdef UPDATE_FUNCTIONAL_ON_FAIL
150 try
151#endif
152 {
153 // RAII object for GPIO unlock / lock
154 GpioLock gpioLock(getGpio());
Patrick Ventureb28f4322018-09-14 10:19:14 -0700155
Brandon Kim79205b22019-06-20 12:18:24 -0700156 // Retry for up to a second if device is busy
157 // or has a transient error.
158 val =
159 _ioAccess->read(_sensor.first, _sensor.second,
160 hwmon::entry::cinput, std::get<size_t>(retryIO),
161 std::get<std::chrono::milliseconds>(retryIO));
Patrick Ventureb28f4322018-09-14 10:19:14 -0700162
Brandon Kim79205b22019-06-20 12:18:24 -0700163 val = adjustValue(val);
164 }
165#ifdef UPDATE_FUNCTIONAL_ON_FAIL
166 catch (const std::system_error& e)
167 {
168 // Catch the exception here and update the functional property.
169 // By catching the exception, it will not propagate it up the stack
170 // and thus the code will skip the "Remove RCs" check in
171 // MainLoop::getObject and will not exit on failure.
172 statusIface->functional(false);
173 }
174#endif
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500175 }
176
Patrick Venture043d3232018-08-31 10:10:53 -0700177 auto iface =
178 std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500179 iface->value(val);
180
181 hwmon::Attributes attrs;
Patrick Venture12659aa2018-12-19 13:58:43 -0800182 if (hwmon::getAttributes(_sensor.first, attrs))
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500183 {
184 iface->unit(hwmon::getUnit(attrs));
James Feistee73f5b2018-08-01 16:31:42 -0700185
186 setScale(iface, hwmon::getScale(attrs), val);
187
Patrick Venture12659aa2018-12-19 13:58:43 -0800188 _scale = hwmon::getScale(attrs);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500189 }
190
Patrick Venture12659aa2018-12-19 13:58:43 -0800191 auto maxValue = env::getEnv("MAXVALUE", _sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700192 if (!maxValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500193 {
194 iface->maxValue(std::stoll(maxValue));
195 }
Patrick Venture12659aa2018-12-19 13:58:43 -0800196 auto minValue = env::getEnv("MINVALUE", _sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700197 if (!minValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500198 {
199 iface->minValue(std::stoll(minValue));
200 }
201
202 obj[InterfaceType::VALUE] = iface;
203 return iface;
204}
205
Matthew Barth2e41b132018-05-07 14:15:45 -0500206std::shared_ptr<StatusObject> Sensor::addStatus(ObjectInfo& info)
Matthew Barth35819382018-04-18 14:53:01 -0500207{
Patrick Venture9e997b42019-03-08 13:42:10 -0800208 namespace fs = std::filesystem;
Matthew Barth35819382018-04-18 14:53:01 -0500209
210 std::shared_ptr<StatusObject> iface = nullptr;
Matthew Barth35819382018-04-18 14:53:01 -0500211 auto& objPath = std::get<std::string>(info);
Patrick Venture62067232019-06-19 17:39:33 -0700212 auto& obj = std::get<InterfaceMap>(info);
Matthew Barth35819382018-04-18 14:53:01 -0500213
214 // Check if fault sysfs file exists
Patrick Venture12659aa2018-12-19 13:58:43 -0800215 std::string faultName = _sensor.first;
216 std::string faultID = _sensor.second;
Matthew Barth35819382018-04-18 14:53:01 -0500217 std::string entry = hwmon::entry::fault;
218
Brandon Kim86dcac82019-06-18 17:48:51 -0700219 bool functional = true;
Patrick Venture043d3232018-08-31 10:10:53 -0700220 auto sysfsFullPath =
Patrick Venture12659aa2018-12-19 13:58:43 -0800221 sysfs::make_sysfs_path(_ioAccess->path(), faultName, faultID, entry);
Matthew Barth35819382018-04-18 14:53:01 -0500222 if (fs::exists(sysfsFullPath))
223 {
Brandon Kim86dcac82019-06-18 17:48:51 -0700224 _hasFaultFile = true;
Matthew Barth35819382018-04-18 14:53:01 -0500225 try
226 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800227 uint32_t fault = _ioAccess->read(faultName, faultID, entry,
228 hwmonio::retries, hwmonio::delay);
Matthew Barth35819382018-04-18 14:53:01 -0500229 if (fault != 0)
230 {
231 functional = false;
232 }
233 }
234 catch (const std::system_error& e)
235 {
Patrick Venture043d3232018-08-31 10:10:53 -0700236 using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::
237 Error;
238 using metadata = xyz::openbmc_project::Sensor::Device::ReadFailure;
Matthew Barth35819382018-04-18 14:53:01 -0500239
Patrick Venture12659aa2018-12-19 13:58:43 -0800240 report<ReadFailure>(
241 metadata::CALLOUT_ERRNO(e.code().value()),
242 metadata::CALLOUT_DEVICE_PATH(_devPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500243
Patrick Venture043d3232018-08-31 10:10:53 -0700244 log<level::INFO>(
245 "Logging failing sysfs file",
246 phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500247 }
Matthew Barth35819382018-04-18 14:53:01 -0500248 }
249
Brandon Kim86dcac82019-06-18 17:48:51 -0700250 static constexpr bool deferSignals = true;
251 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
252
253 iface = std::make_shared<StatusObject>(bus, objPath.c_str(), deferSignals);
254 // Set functional property
255 iface->functional(functional);
256
257 obj[InterfaceType::STATUS] = iface;
258
Matthew Barth35819382018-04-18 14:53:01 -0500259 return iface;
260}
261
Brandon Kimdb76d492019-06-17 11:53:04 -0700262GpioLock::GpioLock(const gpioplus::HandleInterface* handle) : _handle(handle)
263{
264 unlockGpio();
265}
266
267GpioLock::~GpioLock()
268{
269 lockGpio();
270}
271
272void GpioLock::unlockGpio()
Patrick Ventureb28f4322018-09-14 10:19:14 -0700273{
Patrick Venture12659aa2018-12-19 13:58:43 -0800274 if (_handle)
Patrick Ventureb28f4322018-09-14 10:19:14 -0700275 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800276 _handle->setValues({1});
277 std::this_thread::sleep_for(_pause);
Patrick Ventureb28f4322018-09-14 10:19:14 -0700278 }
279}
280
Brandon Kimdb76d492019-06-17 11:53:04 -0700281void GpioLock::lockGpio()
Patrick Ventureb28f4322018-09-14 10:19:14 -0700282{
Patrick Venture12659aa2018-12-19 13:58:43 -0800283 if (_handle)
Patrick Ventureb28f4322018-09-14 10:19:14 -0700284 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800285 _handle->setValues({0});
Patrick Ventureb28f4322018-09-14 10:19:14 -0700286 }
287}
288
Matthew Barth35819382018-04-18 14:53:01 -0500289} // namespace sensor