blob: e21f4b0860795d6123093336493523b343aedaac [file] [log] [blame]
James Feist6714a252018-09-10 15:26:18 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103017#include "IntelCPUSensor.hpp"
18
Ed Tanouseacbfdd2024-04-04 12:00:24 -070019#include "SensorPaths.hpp"
20#include "Thresholds.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103021#include "Utils.hpp"
Ed Tanouseacbfdd2024-04-04 12:00:24 -070022#include "sensor.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103023
Ed Tanouseacbfdd2024-04-04 12:00:24 -070024#include <fcntl.h>
James Feist6714a252018-09-10 15:26:18 -070025#include <unistd.h>
26
James Feist6714a252018-09-10 15:26:18 -070027#include <boost/algorithm/string/replace.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070028#include <boost/asio/error.hpp>
29#include <boost/asio/io_context.hpp>
30#include <boost/asio/posix/descriptor_base.hpp>
31#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070032#include <sdbusplus/asio/connection.hpp>
33#include <sdbusplus/asio/object_server.hpp>
34
Ed Tanouseacbfdd2024-04-04 12:00:24 -070035#include <algorithm>
36#include <chrono>
Ed Tanous2049bd22022-07-09 07:20:26 -070037#include <cstddef>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070038#include <cstdint>
39#include <functional>
James Feist6714a252018-09-10 15:26:18 -070040#include <iostream>
41#include <limits>
Patrick Venture96e97db2019-10-31 13:44:38 -070042#include <memory>
Patrick Venture96e97db2019-10-31 13:44:38 -070043#include <stdexcept>
James Feist6714a252018-09-10 15:26:18 -070044#include <string>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070045#include <tuple>
46#include <utility>
Patrick Venture96e97db2019-10-31 13:44:38 -070047#include <vector>
James Feist6714a252018-09-10 15:26:18 -070048
Thu Nguyen255da6b2022-07-29 10:05:52 +070049IntelCPUSensor::IntelCPUSensor(
50 const std::string& path, const std::string& objectType,
51 sdbusplus::asio::object_server& objectServer,
52 std::shared_ptr<sdbusplus::asio::connection>& conn,
Ed Tanous1f978632023-02-28 18:16:39 -080053 boost::asio::io_context& io, const std::string& sensorName,
Thu Nguyen255da6b2022-07-29 10:05:52 +070054 std::vector<thresholds::Threshold>&& thresholdsIn,
55 const std::string& sensorConfiguration, int cpuId, bool show,
56 double dtsOffset) :
Zhikui Renda98f092021-11-01 09:41:08 -070057 Sensor(escapeName(sensorName), std::move(thresholdsIn), sensorConfiguration,
58 objectType, false, false, 0, 0, conn, PowerState::on),
Ed Tanous2049bd22022-07-09 07:20:26 -070059 objServer(objectServer), inputDev(io), waitTimer(io),
Ed Tanousa771f6a2022-01-14 09:36:51 -080060 nameTcontrol("Tcontrol CPU" + std::to_string(cpuId)), path(path),
Brad Bishopfbb44ad2019-11-08 09:42:37 -050061 privTcontrol(std::numeric_limits<double>::quiet_NaN()),
Thu Nguyen255da6b2022-07-29 10:05:52 +070062 dtsOffset(dtsOffset), show(show), pollTime(IntelCPUSensor::sensorPollMs)
Ed Tanousb429f312022-06-27 16:09:53 -070063
James Feist6714a252018-09-10 15:26:18 -070064{
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -080065 if (show)
James Feist6714a252018-09-10 15:26:18 -070066 {
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +020067 if (auto fileParts = splitFileName(path))
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -080068 {
Zbigniew Kurzynskidbfd4662020-09-28 18:06:00 +020069 auto& [type, nr, item] = *fileParts;
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020070 std::string interfacePath;
Ed Tanousa771f6a2022-01-14 09:36:51 -080071 const char* units = nullptr;
Ed Tanous2049bd22022-07-09 07:20:26 -070072 if (type == "power")
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020073 {
74 interfacePath = "/xyz/openbmc_project/sensors/power/" + name;
Zev Weiss6b6891c2021-04-22 02:46:21 -050075 units = sensor_paths::unitWatts;
Andrei Kartashev6736d4b2020-12-18 18:59:21 +030076 minValue = 0;
77 maxValue = 511;
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020078 }
79 else
80 {
Patrick Williams779c96a2023-05-10 07:50:42 -050081 interfacePath = "/xyz/openbmc_project/sensors/temperature/" +
82 name;
Zev Weiss6b6891c2021-04-22 02:46:21 -050083 units = sensor_paths::unitDegreesC;
Andrei Kartashev6736d4b2020-12-18 18:59:21 +030084 minValue = -128;
85 maxValue = 127;
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020086 }
James Feist078f2322019-03-08 11:09:05 -080087
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020088 sensorInterface = objectServer.add_interface(
89 interfacePath, "xyz.openbmc_project.Sensor.Value");
Jayashree Dhanapal56678082022-01-04 17:27:20 +053090 for (const auto& threshold : thresholds)
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020091 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053092 std::string interface =
93 thresholds::getInterface(threshold.level);
94 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
95 objectServer.add_interface(interfacePath, interface);
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020096 }
97 association = objectServer.add_interface(interfacePath,
98 association::interface);
99
Andrei Kartashev39287412022-02-04 16:04:47 +0300100 setInitialProperties(units);
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +0200101 }
James Feist6714a252018-09-10 15:26:18 -0700102 }
James Feist961bf092020-07-01 16:38:12 -0700103
104 // call setup always as not all sensors call setInitialProperties
James Feist71d31b22019-01-02 16:57:54 -0800105 setupPowerMatch(conn);
James Feist6714a252018-09-10 15:26:18 -0700106}
107
Thu Nguyen255da6b2022-07-29 10:05:52 +0700108IntelCPUSensor::~IntelCPUSensor()
James Feist6714a252018-09-10 15:26:18 -0700109{
110 // close the input dev to cancel async operations
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700111 inputDev.close();
112 waitTimer.cancel();
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800113 if (show)
114 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530115 for (const auto& iface : thresholdInterfaces)
116 {
117 objServer.remove_interface(iface);
118 }
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800119 objServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800120 objServer.remove_interface(association);
Arun P. Mohananb782eec2021-10-18 16:22:09 +0530121 objServer.remove_interface(availableInterface);
122 objServer.remove_interface(operationalInterface);
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800123 }
James Feist6714a252018-09-10 15:26:18 -0700124}
125
Ed Tanous201a1012024-04-03 18:07:28 -0700126void IntelCPUSensor::restartRead()
James Feist6714a252018-09-10 15:26:18 -0700127{
Thu Nguyen255da6b2022-07-29 10:05:52 +0700128 std::weak_ptr<IntelCPUSensor> weakRef = weak_from_this();
Ed Tanous83db50c2023-03-01 10:20:24 -0800129 waitTimer.expires_after(std::chrono::milliseconds(pollTime));
Arun Lal K M84545712021-12-31 13:29:56 +0000130 waitTimer.async_wait([weakRef](const boost::system::error_code& ec) {
131 if (ec == boost::asio::error::operation_aborted)
132 {
133 std::cerr << "Failed to reschedule\n";
134 return;
135 }
Thu Nguyen255da6b2022-07-29 10:05:52 +0700136 std::shared_ptr<IntelCPUSensor> self = weakRef.lock();
Arun P. Mohanan04d05062021-10-29 20:30:26 +0530137
Arun Lal K M84545712021-12-31 13:29:56 +0000138 if (self)
139 {
140 self->setupRead();
141 }
142 });
143}
144
Ed Tanous201a1012024-04-03 18:07:28 -0700145void IntelCPUSensor::setupRead()
Arun Lal K M84545712021-12-31 13:29:56 +0000146{
James Feistc22b8422020-07-07 14:40:39 -0700147 if (readingStateGood())
148 {
149 inputDev.close();
Ed Tanous99c44092022-01-14 09:59:09 -0800150
151 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
Arun Lal K M84545712021-12-31 13:29:56 +0000152 fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
153 if (fd < 0)
James Feistc22b8422020-07-07 14:40:39 -0700154 {
155 std::cerr << name << " unable to open fd!\n";
Arun Lal K M84545712021-12-31 13:29:56 +0000156 return;
James Feistc22b8422020-07-07 14:40:39 -0700157 }
Arun Lal K M84545712021-12-31 13:29:56 +0000158
159 inputDev.assign(fd);
James Feistc22b8422020-07-07 14:40:39 -0700160 }
161 else
162 {
James Feistc22b8422020-07-07 14:40:39 -0700163 markAvailable(false);
Arun Lal K M84545712021-12-31 13:29:56 +0000164 updateValue(std::numeric_limits<double>::quiet_NaN());
165 restartRead();
166 return;
James Feistc22b8422020-07-07 14:40:39 -0700167 }
Arun Lal K M84545712021-12-31 13:29:56 +0000168
Thu Nguyen255da6b2022-07-29 10:05:52 +0700169 std::weak_ptr<IntelCPUSensor> weakRef = weak_from_this();
Arun Lal K M84545712021-12-31 13:29:56 +0000170 inputDev.async_wait(boost::asio::posix::descriptor_base::wait_read,
171 [weakRef](const boost::system::error_code& ec) {
Thu Nguyen255da6b2022-07-29 10:05:52 +0700172 std::shared_ptr<IntelCPUSensor> self = weakRef.lock();
Arun Lal K M84545712021-12-31 13:29:56 +0000173
Ed Tanousbb679322022-05-16 16:10:00 -0700174 if (self)
175 {
176 self->handleResponse(ec);
177 }
178 });
James Feist6714a252018-09-10 15:26:18 -0700179}
180
Ed Tanous201a1012024-04-03 18:07:28 -0700181void IntelCPUSensor::updateMinMaxValues()
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200182{
183 const boost::container::flat_map<
184 std::string,
185 std::vector<std::tuple<const char*, std::reference_wrapper<double>,
186 const char*>>>
187 map = {
188 {
189 "cap",
190 {
191 std::make_tuple("cap_max", std::ref(maxValue), "MaxValue"),
192 std::make_tuple("cap_min", std::ref(minValue), "MinValue"),
193 },
194 },
195 };
196
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200197 if (auto fileParts = splitFileName(path))
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200198 {
Zbigniew Kurzynskidbfd4662020-09-28 18:06:00 +0200199 auto& [fileType, fileNr, fileItem] = *fileParts;
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200200 const auto mapIt = map.find(fileItem);
201 if (mapIt != map.cend())
202 {
203 for (const auto& vectorItem : mapIt->second)
204 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700205 const auto& [suffix, oldValue, dbusName] = vectorItem;
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200206 auto attrPath = boost::replace_all_copy(path, fileItem, suffix);
Patrick Williams779c96a2023-05-10 07:50:42 -0500207 if (auto newVal = readFile(attrPath,
208 IntelCPUSensor::sensorScaleFactor))
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200209 {
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200210 updateProperty(sensorInterface, oldValue, *newVal,
211 dbusName);
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200212 }
213 else
214 {
215 if (isPowerOn())
216 {
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200217 updateProperty(sensorInterface, oldValue, 0, dbusName);
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200218 }
219 else
220 {
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200221 updateProperty(sensorInterface, oldValue,
222 std::numeric_limits<double>::quiet_NaN(),
223 dbusName);
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200224 }
225 }
226 }
227 }
228 }
229}
230
Thu Nguyen255da6b2022-07-29 10:05:52 +0700231void IntelCPUSensor::handleResponse(const boost::system::error_code& err)
James Feist6714a252018-09-10 15:26:18 -0700232{
Arun Lal K M84545712021-12-31 13:29:56 +0000233 if ((err == boost::system::errc::bad_file_descriptor) ||
234 (err == boost::asio::error::misc_errors::not_found))
James Feist6714a252018-09-10 15:26:18 -0700235 {
236 return; // we're being destroyed
237 }
Ed Tanous8a57ec02020-10-09 12:46:52 -0700238 if (err == boost::system::errc::operation_canceled)
James Feist838529b2020-09-02 16:57:05 -0700239 {
240 if (readingStateGood())
241 {
242 if (!loggedInterfaceDown)
243 {
244 std::cerr << name << " interface down!\n";
245 loggedInterfaceDown = true;
246 }
Thu Nguyen255da6b2022-07-29 10:05:52 +0700247 pollTime = static_cast<size_t>(IntelCPUSensor::sensorPollMs) * 10U;
James Feist838529b2020-09-02 16:57:05 -0700248 markFunctional(false);
249 }
250 return;
251 }
252 loggedInterfaceDown = false;
Arun Lal K M84545712021-12-31 13:29:56 +0000253
254 if (err)
James Feist6714a252018-09-10 15:26:18 -0700255 {
Arun Lal K M84545712021-12-31 13:29:56 +0000256 pollTime = sensorFailedPollTimeMs;
257 incrementError();
258 return;
259 }
260
261 static constexpr uint32_t bufLen = 128;
262 std::string response;
263 response.resize(bufLen);
264 int rdLen = 0;
265
266 if (fd >= 0)
267 {
268 rdLen = pread(fd, response.data(), bufLen, 0);
269 }
270
271 if (rdLen > 0)
272 {
James Feist6714a252018-09-10 15:26:18 -0700273 try
274 {
Zhikui Rend3da1282020-09-11 17:02:01 -0700275 rawValue = std::stod(response);
Thu Nguyen255da6b2022-07-29 10:05:52 +0700276 double nvalue = rawValue / IntelCPUSensor::sensorScaleFactor;
Josh Lehan833661a2020-03-04 17:35:41 -0800277
278 if (show)
James Feist6714a252018-09-10 15:26:18 -0700279 {
Josh Lehan833661a2020-03-04 17:35:41 -0800280 updateValue(nvalue);
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800281 }
Josh Lehan833661a2020-03-04 17:35:41 -0800282 else
283 {
284 value = nvalue;
285 }
Zbigniew Kurzynski98be9842020-09-07 18:49:15 +0200286 if (minMaxReadCounter++ % 8 == 0)
287 {
288 updateMinMaxValues();
289 }
Josh Lehan833661a2020-03-04 17:35:41 -0800290
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800291 double gTcontrol = gCpuSensors[nameTcontrol]
292 ? gCpuSensors[nameTcontrol]->value
293 : std::numeric_limits<double>::quiet_NaN();
294 if (gTcontrol != privTcontrol)
295 {
296 privTcontrol = gTcontrol;
297
298 if (!thresholds.empty())
299 {
300 std::vector<thresholds::Threshold> newThresholds;
Thu Nguyen255da6b2022-07-29 10:05:52 +0700301 if (parseThresholdsFromAttr(
302 newThresholds, path,
Chris Sidesa3279232023-04-24 16:08:13 -0500303 IntelCPUSensor::sensorScaleFactor, dtsOffset, 0))
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800304 {
305 if (!std::equal(thresholds.begin(), thresholds.end(),
306 newThresholds.begin(),
307 newThresholds.end()))
308 {
309 thresholds = newThresholds;
310 if (show)
311 {
312 thresholds::updateThresholds(this);
313 }
314 }
315 }
316 else
317 {
318 std::cerr << "Failure to update thresholds for " << name
319 << "\n";
320 }
Jae Hyun Yoo95b8a2d2019-02-25 20:15:09 -0800321 }
322 }
James Feist6714a252018-09-10 15:26:18 -0700323 }
James Feistd8705872019-02-08 13:26:09 -0800324 catch (const std::invalid_argument&)
James Feist6714a252018-09-10 15:26:18 -0700325 {
James Feist961bf092020-07-01 16:38:12 -0700326 incrementError();
James Feist6714a252018-09-10 15:26:18 -0700327 }
328 }
329 else
330 {
James Feist1169eb42018-10-31 10:08:47 -0700331 pollTime = sensorFailedPollTimeMs;
James Feist961bf092020-07-01 16:38:12 -0700332 incrementError();
James Feist6714a252018-09-10 15:26:18 -0700333 }
Arun Lal K M84545712021-12-31 13:29:56 +0000334 restartRead();
James Feist6714a252018-09-10 15:26:18 -0700335}
336
Ed Tanous201a1012024-04-03 18:07:28 -0700337void IntelCPUSensor::checkThresholds()
James Feist6714a252018-09-10 15:26:18 -0700338{
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800339 if (show)
340 {
341 thresholds::checkThresholds(this);
342 }
James Feist6714a252018-09-10 15:26:18 -0700343}