blob: a88410be2cac1cfa6d213f7d91912e6338e02ef1 [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 Kimdb76d492019-06-17 11:53:04 -0700149 // RAII object for GPIO unlock / lock
150 GpioLock gpioLock(getGpio());
Patrick Ventureb28f4322018-09-14 10:19:14 -0700151
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500152 // Retry for up to a second if device is busy
153 // or has a transient error.
Patrick Venture12659aa2018-12-19 13:58:43 -0800154 val = _ioAccess->read(_sensor.first, _sensor.second,
155 hwmon::entry::cinput, std::get<size_t>(retryIO),
156 std::get<std::chrono::milliseconds>(retryIO));
Patrick Ventureb28f4322018-09-14 10:19:14 -0700157
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500158 val = adjustValue(val);
159 }
160
Patrick Venture043d3232018-08-31 10:10:53 -0700161 auto iface =
162 std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500163 iface->value(val);
164
165 hwmon::Attributes attrs;
Patrick Venture12659aa2018-12-19 13:58:43 -0800166 if (hwmon::getAttributes(_sensor.first, attrs))
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500167 {
168 iface->unit(hwmon::getUnit(attrs));
James Feistee73f5b2018-08-01 16:31:42 -0700169
170 setScale(iface, hwmon::getScale(attrs), val);
171
Patrick Venture12659aa2018-12-19 13:58:43 -0800172 _scale = hwmon::getScale(attrs);
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500173 }
174
Patrick Venture12659aa2018-12-19 13:58:43 -0800175 auto maxValue = env::getEnv("MAXVALUE", _sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700176 if (!maxValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500177 {
178 iface->maxValue(std::stoll(maxValue));
179 }
Patrick Venture12659aa2018-12-19 13:58:43 -0800180 auto minValue = env::getEnv("MINVALUE", _sensor);
Patrick Venture043d3232018-08-31 10:10:53 -0700181 if (!minValue.empty())
Matthew Barthcb3daaf2018-05-07 15:03:16 -0500182 {
183 iface->minValue(std::stoll(minValue));
184 }
185
186 obj[InterfaceType::VALUE] = iface;
187 return iface;
188}
189
Matthew Barth2e41b132018-05-07 14:15:45 -0500190std::shared_ptr<StatusObject> Sensor::addStatus(ObjectInfo& info)
Matthew Barth35819382018-04-18 14:53:01 -0500191{
Patrick Venture9e997b42019-03-08 13:42:10 -0800192 namespace fs = std::filesystem;
Matthew Barth35819382018-04-18 14:53:01 -0500193
194 std::shared_ptr<StatusObject> iface = nullptr;
Matthew Barth35819382018-04-18 14:53:01 -0500195 auto& objPath = std::get<std::string>(info);
Patrick Venture62067232019-06-19 17:39:33 -0700196 auto& obj = std::get<InterfaceMap>(info);
Matthew Barth35819382018-04-18 14:53:01 -0500197
198 // Check if fault sysfs file exists
Patrick Venture12659aa2018-12-19 13:58:43 -0800199 std::string faultName = _sensor.first;
200 std::string faultID = _sensor.second;
Matthew Barth35819382018-04-18 14:53:01 -0500201 std::string entry = hwmon::entry::fault;
202
Brandon Kim86dcac82019-06-18 17:48:51 -0700203 bool functional = true;
Patrick Venture043d3232018-08-31 10:10:53 -0700204 auto sysfsFullPath =
Patrick Venture12659aa2018-12-19 13:58:43 -0800205 sysfs::make_sysfs_path(_ioAccess->path(), faultName, faultID, entry);
Matthew Barth35819382018-04-18 14:53:01 -0500206 if (fs::exists(sysfsFullPath))
207 {
Brandon Kim86dcac82019-06-18 17:48:51 -0700208 _hasFaultFile = true;
Matthew Barth35819382018-04-18 14:53:01 -0500209 try
210 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800211 uint32_t fault = _ioAccess->read(faultName, faultID, entry,
212 hwmonio::retries, hwmonio::delay);
Matthew Barth35819382018-04-18 14:53:01 -0500213 if (fault != 0)
214 {
215 functional = false;
216 }
217 }
218 catch (const std::system_error& e)
219 {
Patrick Venture043d3232018-08-31 10:10:53 -0700220 using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::
221 Error;
222 using metadata = xyz::openbmc_project::Sensor::Device::ReadFailure;
Matthew Barth35819382018-04-18 14:53:01 -0500223
Patrick Venture12659aa2018-12-19 13:58:43 -0800224 report<ReadFailure>(
225 metadata::CALLOUT_ERRNO(e.code().value()),
226 metadata::CALLOUT_DEVICE_PATH(_devPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500227
Patrick Venture043d3232018-08-31 10:10:53 -0700228 log<level::INFO>(
229 "Logging failing sysfs file",
230 phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str()));
Matthew Barth35819382018-04-18 14:53:01 -0500231 }
Matthew Barth35819382018-04-18 14:53:01 -0500232 }
233
Brandon Kim86dcac82019-06-18 17:48:51 -0700234 static constexpr bool deferSignals = true;
235 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
236
237 iface = std::make_shared<StatusObject>(bus, objPath.c_str(), deferSignals);
238 // Set functional property
239 iface->functional(functional);
240
241 obj[InterfaceType::STATUS] = iface;
242
Matthew Barth35819382018-04-18 14:53:01 -0500243 return iface;
244}
245
Brandon Kimdb76d492019-06-17 11:53:04 -0700246GpioLock::GpioLock(const gpioplus::HandleInterface* handle) : _handle(handle)
247{
248 unlockGpio();
249}
250
251GpioLock::~GpioLock()
252{
253 lockGpio();
254}
255
256void GpioLock::unlockGpio()
Patrick Ventureb28f4322018-09-14 10:19:14 -0700257{
Patrick Venture12659aa2018-12-19 13:58:43 -0800258 if (_handle)
Patrick Ventureb28f4322018-09-14 10:19:14 -0700259 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800260 _handle->setValues({1});
261 std::this_thread::sleep_for(_pause);
Patrick Ventureb28f4322018-09-14 10:19:14 -0700262 }
263}
264
Brandon Kimdb76d492019-06-17 11:53:04 -0700265void GpioLock::lockGpio()
Patrick Ventureb28f4322018-09-14 10:19:14 -0700266{
Patrick Venture12659aa2018-12-19 13:58:43 -0800267 if (_handle)
Patrick Ventureb28f4322018-09-14 10:19:14 -0700268 {
Patrick Venture12659aa2018-12-19 13:58:43 -0800269 _handle->setValues({0});
Patrick Ventureb28f4322018-09-14 10:19:14 -0700270 }
271}
272
Matthew Barth35819382018-04-18 14:53:01 -0500273} // namespace sensor