blob: 0c555c375c3e4d6528067006f3dce4ffd219c5c3 [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>
George Liu4ab892a2025-02-20 14:35:49 +080032#include <phosphor-logging/lg2.hpp>
James Feist38fb5982020-05-28 10:09:54 -070033#include <sdbusplus/asio/connection.hpp>
34#include <sdbusplus/asio/object_server.hpp>
35
Ed Tanouseacbfdd2024-04-04 12:00:24 -070036#include <algorithm>
37#include <chrono>
Ed Tanous2049bd22022-07-09 07:20:26 -070038#include <cstddef>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070039#include <cstdint>
40#include <functional>
James Feist6714a252018-09-10 15:26:18 -070041#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()),
Ed Tanousaba6fca2025-09-29 13:53:20 -070062 dtsOffset(dtsOffset), show(show)
James Feist6714a252018-09-10 15:26:18 -070063{
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -080064 if (show)
James Feist6714a252018-09-10 15:26:18 -070065 {
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +020066 if (auto fileParts = splitFileName(path))
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -080067 {
Zbigniew Kurzynskidbfd4662020-09-28 18:06:00 +020068 auto& [type, nr, item] = *fileParts;
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020069 std::string interfacePath;
Ed Tanousa771f6a2022-01-14 09:36:51 -080070 const char* units = nullptr;
Ed Tanous2049bd22022-07-09 07:20:26 -070071 if (type == "power")
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020072 {
73 interfacePath = "/xyz/openbmc_project/sensors/power/" + name;
Zev Weiss6b6891c2021-04-22 02:46:21 -050074 units = sensor_paths::unitWatts;
Andrei Kartashev6736d4b2020-12-18 18:59:21 +030075 minValue = 0;
76 maxValue = 511;
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020077 }
78 else
79 {
Patrick Williams779c96a2023-05-10 07:50:42 -050080 interfacePath = "/xyz/openbmc_project/sensors/temperature/" +
81 name;
Zev Weiss6b6891c2021-04-22 02:46:21 -050082 units = sensor_paths::unitDegreesC;
Andrei Kartashev6736d4b2020-12-18 18:59:21 +030083 minValue = -128;
84 maxValue = 127;
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020085 }
James Feist078f2322019-03-08 11:09:05 -080086
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020087 sensorInterface = objectServer.add_interface(
88 interfacePath, "xyz.openbmc_project.Sensor.Value");
Jayashree Dhanapal56678082022-01-04 17:27:20 +053089 for (const auto& threshold : thresholds)
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020090 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053091 std::string interface =
92 thresholds::getInterface(threshold.level);
93 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
94 objectServer.add_interface(interfacePath, interface);
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +020095 }
96 association = objectServer.add_interface(interfacePath,
97 association::interface);
98
Andrei Kartashev39287412022-02-04 16:04:47 +030099 setInitialProperties(units);
Zbigniew Kurzynski0a4c4802020-04-01 11:22:27 +0200100 }
James Feist6714a252018-09-10 15:26:18 -0700101 }
James Feist961bf092020-07-01 16:38:12 -0700102
103 // call setup always as not all sensors call setInitialProperties
James Feist71d31b22019-01-02 16:57:54 -0800104 setupPowerMatch(conn);
James Feist6714a252018-09-10 15:26:18 -0700105}
106
Thu Nguyen255da6b2022-07-29 10:05:52 +0700107IntelCPUSensor::~IntelCPUSensor()
James Feist6714a252018-09-10 15:26:18 -0700108{
109 // close the input dev to cancel async operations
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700110 inputDev.close();
111 waitTimer.cancel();
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800112 if (show)
113 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530114 for (const auto& iface : thresholdInterfaces)
115 {
116 objServer.remove_interface(iface);
117 }
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800118 objServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800119 objServer.remove_interface(association);
Arun P. Mohananb782eec2021-10-18 16:22:09 +0530120 objServer.remove_interface(availableInterface);
121 objServer.remove_interface(operationalInterface);
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800122 }
James Feist6714a252018-09-10 15:26:18 -0700123}
124
Ed Tanous201a1012024-04-03 18:07:28 -0700125void IntelCPUSensor::restartRead()
James Feist6714a252018-09-10 15:26:18 -0700126{
Thu Nguyen255da6b2022-07-29 10:05:52 +0700127 std::weak_ptr<IntelCPUSensor> weakRef = weak_from_this();
Ed Tanous83db50c2023-03-01 10:20:24 -0800128 waitTimer.expires_after(std::chrono::milliseconds(pollTime));
Arun Lal K M84545712021-12-31 13:29:56 +0000129 waitTimer.async_wait([weakRef](const boost::system::error_code& ec) {
130 if (ec == boost::asio::error::operation_aborted)
131 {
George Liu4ab892a2025-02-20 14:35:49 +0800132 lg2::error("Failed to reschedule");
Arun Lal K M84545712021-12-31 13:29:56 +0000133 return;
134 }
Thu Nguyen255da6b2022-07-29 10:05:52 +0700135 std::shared_ptr<IntelCPUSensor> self = weakRef.lock();
Arun P. Mohanan04d05062021-10-29 20:30:26 +0530136
Arun Lal K M84545712021-12-31 13:29:56 +0000137 if (self)
138 {
139 self->setupRead();
140 }
141 });
142}
143
Ed Tanous201a1012024-04-03 18:07:28 -0700144void IntelCPUSensor::setupRead()
Arun Lal K M84545712021-12-31 13:29:56 +0000145{
James Feistc22b8422020-07-07 14:40:39 -0700146 if (readingStateGood())
147 {
148 inputDev.close();
Ed Tanous99c44092022-01-14 09:59:09 -0800149
150 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
Arun Lal K M84545712021-12-31 13:29:56 +0000151 fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
152 if (fd < 0)
James Feistc22b8422020-07-07 14:40:39 -0700153 {
George Liu4ab892a2025-02-20 14:35:49 +0800154 lg2::error("'{NAME}' unable to open fd!", "NAME", name);
Arun Lal K M84545712021-12-31 13:29:56 +0000155 return;
James Feistc22b8422020-07-07 14:40:39 -0700156 }
Arun Lal K M84545712021-12-31 13:29:56 +0000157
158 inputDev.assign(fd);
James Feistc22b8422020-07-07 14:40:39 -0700159 }
160 else
161 {
James Feistc22b8422020-07-07 14:40:39 -0700162 markAvailable(false);
Konstantin Aladyshev9b992932025-01-30 13:54:31 +0300163 if (show)
164 {
165 updateValue(std::numeric_limits<double>::quiet_NaN());
166 }
167 else
168 {
169 value = std::numeric_limits<double>::quiet_NaN();
170 }
Arun Lal K M84545712021-12-31 13:29:56 +0000171 restartRead();
172 return;
James Feistc22b8422020-07-07 14:40:39 -0700173 }
Arun Lal K M84545712021-12-31 13:29:56 +0000174
Thu Nguyen255da6b2022-07-29 10:05:52 +0700175 std::weak_ptr<IntelCPUSensor> weakRef = weak_from_this();
Arun Lal K M84545712021-12-31 13:29:56 +0000176 inputDev.async_wait(boost::asio::posix::descriptor_base::wait_read,
177 [weakRef](const boost::system::error_code& ec) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400178 std::shared_ptr<IntelCPUSensor> self =
179 weakRef.lock();
Arun Lal K M84545712021-12-31 13:29:56 +0000180
Patrick Williams2aaf7172024-08-16 15:20:40 -0400181 if (self)
182 {
183 self->handleResponse(ec);
184 }
185 });
James Feist6714a252018-09-10 15:26:18 -0700186}
187
Ed Tanous201a1012024-04-03 18:07:28 -0700188void IntelCPUSensor::updateMinMaxValues()
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200189{
190 const boost::container::flat_map<
191 std::string,
192 std::vector<std::tuple<const char*, std::reference_wrapper<double>,
193 const char*>>>
194 map = {
195 {
196 "cap",
197 {
198 std::make_tuple("cap_max", std::ref(maxValue), "MaxValue"),
199 std::make_tuple("cap_min", std::ref(minValue), "MinValue"),
200 },
201 },
202 };
203
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200204 if (auto fileParts = splitFileName(path))
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200205 {
Zbigniew Kurzynskidbfd4662020-09-28 18:06:00 +0200206 auto& [fileType, fileNr, fileItem] = *fileParts;
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200207 const auto mapIt = map.find(fileItem);
208 if (mapIt != map.cend())
209 {
210 for (const auto& vectorItem : mapIt->second)
211 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700212 const auto& [suffix, oldValue, dbusName] = vectorItem;
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200213 auto attrPath = boost::replace_all_copy(path, fileItem, suffix);
Patrick Williams2aaf7172024-08-16 15:20:40 -0400214 if (auto newVal =
215 readFile(attrPath, IntelCPUSensor::sensorScaleFactor))
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200216 {
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200217 updateProperty(sensorInterface, oldValue, *newVal,
218 dbusName);
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200219 }
220 else
221 {
222 if (isPowerOn())
223 {
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200224 updateProperty(sensorInterface, oldValue, 0, dbusName);
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200225 }
226 else
227 {
Zbigniew Kurzynski4f45e422020-06-09 12:42:15 +0200228 updateProperty(sensorInterface, oldValue,
229 std::numeric_limits<double>::quiet_NaN(),
230 dbusName);
Zbigniew Kurzynski8d8d8d72020-05-29 19:21:24 +0200231 }
232 }
233 }
234 }
235 }
236}
237
Thu Nguyen255da6b2022-07-29 10:05:52 +0700238void IntelCPUSensor::handleResponse(const boost::system::error_code& err)
James Feist6714a252018-09-10 15:26:18 -0700239{
Arun Lal K M84545712021-12-31 13:29:56 +0000240 if ((err == boost::system::errc::bad_file_descriptor) ||
241 (err == boost::asio::error::misc_errors::not_found))
James Feist6714a252018-09-10 15:26:18 -0700242 {
243 return; // we're being destroyed
244 }
Ed Tanous8a57ec02020-10-09 12:46:52 -0700245 if (err == boost::system::errc::operation_canceled)
James Feist838529b2020-09-02 16:57:05 -0700246 {
247 if (readingStateGood())
248 {
249 if (!loggedInterfaceDown)
250 {
George Liu4ab892a2025-02-20 14:35:49 +0800251 lg2::error("'{NAME}' interface down!", "NAME", name);
James Feist838529b2020-09-02 16:57:05 -0700252 loggedInterfaceDown = true;
253 }
Thu Nguyen255da6b2022-07-29 10:05:52 +0700254 pollTime = static_cast<size_t>(IntelCPUSensor::sensorPollMs) * 10U;
James Feist838529b2020-09-02 16:57:05 -0700255 markFunctional(false);
256 }
257 return;
258 }
259 loggedInterfaceDown = false;
Arun Lal K M84545712021-12-31 13:29:56 +0000260
261 if (err)
James Feist6714a252018-09-10 15:26:18 -0700262 {
Arun Lal K M84545712021-12-31 13:29:56 +0000263 pollTime = sensorFailedPollTimeMs;
264 incrementError();
265 return;
266 }
267
268 static constexpr uint32_t bufLen = 128;
269 std::string response;
270 response.resize(bufLen);
271 int rdLen = 0;
272
273 if (fd >= 0)
274 {
275 rdLen = pread(fd, response.data(), bufLen, 0);
276 }
277
278 if (rdLen > 0)
279 {
James Feist6714a252018-09-10 15:26:18 -0700280 try
281 {
Zhikui Rend3da1282020-09-11 17:02:01 -0700282 rawValue = std::stod(response);
Thu Nguyen255da6b2022-07-29 10:05:52 +0700283 double nvalue = rawValue / IntelCPUSensor::sensorScaleFactor;
Josh Lehan833661a2020-03-04 17:35:41 -0800284
285 if (show)
James Feist6714a252018-09-10 15:26:18 -0700286 {
Josh Lehan833661a2020-03-04 17:35:41 -0800287 updateValue(nvalue);
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800288 }
Josh Lehan833661a2020-03-04 17:35:41 -0800289 else
290 {
291 value = nvalue;
292 }
Zbigniew Kurzynski98be9842020-09-07 18:49:15 +0200293 if (minMaxReadCounter++ % 8 == 0)
294 {
295 updateMinMaxValues();
296 }
Josh Lehan833661a2020-03-04 17:35:41 -0800297
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800298 double gTcontrol = gCpuSensors[nameTcontrol]
299 ? gCpuSensors[nameTcontrol]->value
300 : std::numeric_limits<double>::quiet_NaN();
301 if (gTcontrol != privTcontrol)
302 {
303 privTcontrol = gTcontrol;
304
305 if (!thresholds.empty())
306 {
307 std::vector<thresholds::Threshold> newThresholds;
Thu Nguyen255da6b2022-07-29 10:05:52 +0700308 if (parseThresholdsFromAttr(
309 newThresholds, path,
Chris Sidesa3279232023-04-24 16:08:13 -0500310 IntelCPUSensor::sensorScaleFactor, dtsOffset, 0))
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800311 {
312 if (!std::equal(thresholds.begin(), thresholds.end(),
313 newThresholds.begin(),
314 newThresholds.end()))
315 {
316 thresholds = newThresholds;
317 if (show)
318 {
319 thresholds::updateThresholds(this);
320 }
321 }
322 }
323 else
324 {
George Liu4ab892a2025-02-20 14:35:49 +0800325 lg2::error("Failure to update thresholds for '{NAME}'",
326 "NAME", name);
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800327 }
Jae Hyun Yoo95b8a2d2019-02-25 20:15:09 -0800328 }
329 }
James Feist6714a252018-09-10 15:26:18 -0700330 }
James Feistd8705872019-02-08 13:26:09 -0800331 catch (const std::invalid_argument&)
James Feist6714a252018-09-10 15:26:18 -0700332 {
James Feist961bf092020-07-01 16:38:12 -0700333 incrementError();
James Feist6714a252018-09-10 15:26:18 -0700334 }
335 }
336 else
337 {
James Feist1169eb42018-10-31 10:08:47 -0700338 pollTime = sensorFailedPollTimeMs;
James Feist961bf092020-07-01 16:38:12 -0700339 incrementError();
James Feist6714a252018-09-10 15:26:18 -0700340 }
Arun Lal K M84545712021-12-31 13:29:56 +0000341 restartRead();
James Feist6714a252018-09-10 15:26:18 -0700342}
343
Ed Tanous201a1012024-04-03 18:07:28 -0700344void IntelCPUSensor::checkThresholds()
James Feist6714a252018-09-10 15:26:18 -0700345{
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800346 if (show)
347 {
348 thresholds::checkThresholds(this);
349 }
James Feist6714a252018-09-10 15:26:18 -0700350}