blob: fbc4b7d9c9ea2c078ddc9b15e33a4f1d0d09a823 [file] [log] [blame]
James Feist6ef20402019-01-07 16:45:08 -08001/*
2// Copyright (c) 2019 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 "IpmbSensor.hpp"
18
19#include "IpmbSDRSensor.hpp"
Ed Tanouseacbfdd2024-04-04 12:00:24 -070020#include "SensorPaths.hpp"
21#include "Thresholds.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103022#include "Utils.hpp"
23#include "VariantVisitors.hpp"
Ed Tanouseacbfdd2024-04-04 12:00:24 -070024#include "sensor.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103025
Ed Tanouseacbfdd2024-04-04 12:00:24 -070026#include <boost/asio/error.hpp>
27#include <boost/asio/io_context.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070028#include <boost/asio/steady_timer.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070029#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070030#include <sdbusplus/asio/connection.hpp>
31#include <sdbusplus/asio/object_server.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070032#include <sdbusplus/message.hpp>
33#include <sdbusplus/message/native_types.hpp>
James Feist38fb5982020-05-28 10:09:54 -070034
Ed Tanouseacbfdd2024-04-04 12:00:24 -070035#include <algorithm>
36#include <array>
James Feist6ef20402019-01-07 16:45:08 -080037#include <chrono>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070038#include <cstddef>
39#include <cstdint>
James Feist6ef20402019-01-07 16:45:08 -080040#include <iostream>
41#include <limits>
Patrick Venture96e97db2019-10-31 13:44:38 -070042#include <memory>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070043#include <stdexcept>
Patrick Venture96e97db2019-10-31 13:44:38 -070044#include <string>
45#include <tuple>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070046#include <utility>
Patrick Venture96e97db2019-10-31 13:44:38 -070047#include <variant>
James Feist6ef20402019-01-07 16:45:08 -080048#include <vector>
49
50constexpr const bool debug = false;
51
James Feist6ef20402019-01-07 16:45:08 -080052static constexpr double ipmbMaxReading = 0xFF;
53static constexpr double ipmbMinReading = 0;
54
55static constexpr uint8_t meAddress = 1;
56static constexpr uint8_t lun = 0;
Anoop S832a2c62020-11-20 19:21:22 +000057static constexpr uint8_t hostSMbusIndexDefault = 0x03;
Jayashree Dhanapal6ee62942021-12-14 15:22:23 +053058static constexpr uint8_t ipmbBusIndexDefault = 0;
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053059static constexpr float pollRateDefault = 1; // in seconds
James Feist6ef20402019-01-07 16:45:08 -080060
Vijay Khemka682a5cb2019-07-18 17:34:03 -070061static constexpr const char* sensorPathPrefix = "/xyz/openbmc_project/sensors/";
62
James Feist6ef20402019-01-07 16:45:08 -080063IpmbSensor::IpmbSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
Ed Tanous1f978632023-02-28 18:16:39 -080064 boost::asio::io_context& io,
James Feist6ef20402019-01-07 16:45:08 -080065 const std::string& sensorName,
66 const std::string& sensorConfiguration,
67 sdbusplus::asio::object_server& objectServer,
68 std::vector<thresholds::Threshold>&& thresholdData,
Anoop S832a2c62020-11-20 19:21:22 +000069 uint8_t deviceAddress, uint8_t hostSMbusIndex,
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053070 const float pollRate, std::string& sensorTypeName) :
Zhikui Renda98f092021-11-01 09:41:08 -070071 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -070072 sensorConfiguration, "IpmbSensor", false, false, ipmbMaxReading,
73 ipmbMinReading, conn, PowerState::on),
Anoop S832a2c62020-11-20 19:21:22 +000074 deviceAddress(deviceAddress), hostSMbusIndex(hostSMbusIndex),
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053075 sensorPollMs(static_cast<int>(pollRate * 1000)), objectServer(objectServer),
76 waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080077{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070078 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
79
James Feist6ef20402019-01-07 16:45:08 -080080 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070081 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080082
Jayashree Dhanapal56678082022-01-04 17:27:20 +053083 for (const auto& threshold : thresholds)
James Feist6ef20402019-01-07 16:45:08 -080084 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053085 std::string interface = thresholds::getInterface(threshold.level);
86 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
87 objectServer.add_interface(dbusPath, interface);
James Feist6ef20402019-01-07 16:45:08 -080088 }
James Feist2adc95c2019-09-30 14:55:28 -070089 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -080090}
91
92IpmbSensor::~IpmbSensor()
93{
94 waitTimer.cancel();
Jayashree Dhanapal56678082022-01-04 17:27:20 +053095 for (const auto& iface : thresholdInterfaces)
96 {
97 objectServer.remove_interface(iface);
98 }
James Feist6ef20402019-01-07 16:45:08 -080099 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800100 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -0800101}
102
Ed Tanous201a1012024-04-03 18:07:28 -0700103std::string IpmbSensor::getSubTypeUnits() const
Zev Weiss6b6891c2021-04-22 02:46:21 -0500104{
105 switch (subType)
106 {
107 case IpmbSubType::temp:
108 return sensor_paths::unitDegreesC;
109 case IpmbSubType::curr:
110 return sensor_paths::unitAmperes;
111 case IpmbSubType::power:
112 return sensor_paths::unitWatts;
113 case IpmbSubType::volt:
114 return sensor_paths::unitVolts;
115 case IpmbSubType::util:
116 return sensor_paths::unitPercent;
117 default:
118 throw std::runtime_error("Invalid sensor type");
119 }
120}
121
Ed Tanous201a1012024-04-03 18:07:28 -0700122void IpmbSensor::init()
James Feist6ef20402019-01-07 16:45:08 -0800123{
James Feist6ef20402019-01-07 16:45:08 -0800124 loadDefaults();
Andrei Kartashev39287412022-02-04 16:04:47 +0300125 setInitialProperties(getSubTypeUnits());
James Feist6ef20402019-01-07 16:45:08 -0800126 if (initCommand)
127 {
James Feistf7e2c5d2019-02-13 17:27:51 -0800128 runInitCmd();
129 }
130 read();
131}
132
Vikash Chandola1f847972022-09-28 09:47:32 +0000133static void initCmdCb(const std::weak_ptr<IpmbSensor>& weakRef,
134 const boost::system::error_code& ec,
135 const IpmbMethodType& response)
136{
137 std::shared_ptr<IpmbSensor> self = weakRef.lock();
138 if (!self)
139 {
140 return;
141 }
142 const int& status = std::get<0>(response);
143 if (ec || (status != 0))
144 {
145 std::cerr << "Error setting init command for device: " << self->name
146 << "\n";
147 }
148}
149
James Feistf7e2c5d2019-02-13 17:27:51 -0800150void IpmbSensor::runInitCmd()
151{
Vikash Chandola1f847972022-09-28 09:47:32 +0000152 if (!initCommand)
James Feistf7e2c5d2019-02-13 17:27:51 -0800153 {
Vikash Chandola1f847972022-09-28 09:47:32 +0000154 return;
James Feist6ef20402019-01-07 16:45:08 -0800155 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000156 dbusConnection->async_method_call(
157 [weakRef{weak_from_this()}](const boost::system::error_code& ec,
158 const IpmbMethodType& response) {
159 initCmdCb(weakRef, ec, response);
Patrick Williams597e8422023-10-20 11:19:01 -0500160 },
Vikash Chandola1f847972022-09-28 09:47:32 +0000161 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
162 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
163 "sendRequest", commandAddress, netfn, lun, *initCommand, initData);
James Feist6ef20402019-01-07 16:45:08 -0800164}
165
166void IpmbSensor::loadDefaults()
167{
168 if (type == IpmbType::meSensor)
169 {
170 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200171 netfn = ipmi::sensor::netFn;
172 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800173 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700174 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800175 }
176 else if (type == IpmbType::PXE1410CVR)
177 {
178 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200179 netfn = ipmi::me_bridge::netFn;
180 command = ipmi::me_bridge::sendRawPmbus;
181 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700182 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000183 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
184 deviceAddress, 0x00, 0x00, 0x00, 0x00,
185 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700186 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000187 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
188 deviceAddress, 0x00, 0x00, 0x00, 0x00,
189 0x02, 0x00, 0x00, 0x00};
Jayashree-D37322572021-03-19 17:40:56 +0530190 readingFormat = ReadingFormat::linearElevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800191 }
192 else if (type == IpmbType::IR38363VR)
193 {
194 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200195 netfn = ipmi::me_bridge::netFn;
196 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700197 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000198 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
199 deviceAddress, 00, 0x00, 0x00, 0x00,
200 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700201 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800202 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700203 else if (type == IpmbType::ADM1278HSC)
204 {
205 commandAddress = meAddress;
Ed Tanousa771f6a2022-01-14 09:36:51 -0800206 uint8_t snsNum = 0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700207 switch (subType)
208 {
209 case IpmbSubType::temp:
210 case IpmbSubType::curr:
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700211 if (subType == IpmbSubType::temp)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700212 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700213 snsNum = 0x8d;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700214 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700215 else
Ed Tanous8a57ec02020-10-09 12:46:52 -0700216 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700217 snsNum = 0x8c;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700218 }
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200219 netfn = ipmi::me_bridge::netFn;
220 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700221 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
222 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700223 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700224 break;
225 case IpmbSubType::power:
226 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200227 netfn = ipmi::sensor::netFn;
228 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700229 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700230 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700231 break;
232 default:
233 throw std::runtime_error("Invalid sensor type");
234 }
235 }
James Feist6ef20402019-01-07 16:45:08 -0800236 else if (type == IpmbType::mpsVR)
237 {
238 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200239 netfn = ipmi::me_bridge::netFn;
240 command = ipmi::me_bridge::sendRawPmbus;
241 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700242 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000243 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
244 deviceAddress, 0x00, 0x00, 0x00, 0x00,
245 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700246 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000247 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
248 deviceAddress, 0x00, 0x00, 0x00, 0x00,
249 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700250 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800251 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700252 else if (type == IpmbType::SMPro)
253 {
254 // This is an Ampere SMPro reachable via a BMC. For example,
255 // this architecture is used on ADLINK Ampere Altra systems.
256 // See the Ampere Family SoC BMC Interface Specification at
257 // https://amperecomputing.com/customer-connect/products/altra-family-software---firmware
258 // for details of the sensors.
259 commandAddress = 0;
260 netfn = 0x30;
261 command = 0x31;
262 commandData = {0x9e, deviceAddress};
263 switch (subType)
264 {
265 case IpmbSubType::temp:
266 readingFormat = ReadingFormat::nineBit;
267 break;
268 case IpmbSubType::power:
269 readingFormat = ReadingFormat::tenBit;
270 break;
271 case IpmbSubType::curr:
272 case IpmbSubType::volt:
273 readingFormat = ReadingFormat::fifteenBit;
274 break;
275 default:
276 throw std::runtime_error("Invalid sensor type");
277 }
278 }
James Feist6ef20402019-01-07 16:45:08 -0800279 else
280 {
281 throw std::runtime_error("Invalid sensor type");
282 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200283
284 if (subType == IpmbSubType::util)
285 {
286 // Utilization need to be scaled to percent
287 maxValue = 100;
288 minValue = 0;
289 }
James Feist6ef20402019-01-07 16:45:08 -0800290}
291
Ed Tanous201a1012024-04-03 18:07:28 -0700292void IpmbSensor::checkThresholds()
James Feist6ef20402019-01-07 16:45:08 -0800293{
James Feist6ef20402019-01-07 16:45:08 -0800294 thresholds::checkThresholds(this);
295}
296
Ed Tanous828c5a62024-02-09 16:59:22 -0800297bool IpmbSensor::processReading(ReadingFormat readingFormat, uint8_t command,
298 const std::vector<uint8_t>& data, double& resp,
299 size_t errCount)
James Feistd7ae29a2020-06-25 15:42:46 -0700300{
James Feistd7ae29a2020-06-25 15:42:46 -0700301 switch (readingFormat)
302 {
303 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700304 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200305 if (command == ipmi::sensor::getSensorReading &&
306 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700307 {
308 return false;
309 }
James Feist961bf092020-07-01 16:38:12 -0700310 resp = data[0];
311 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700312 }
James Feistd7ae29a2020-06-25 15:42:46 -0700313 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700314 {
James Feistd7ae29a2020-06-25 15:42:46 -0700315 if (data.size() < 4)
316 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700317 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700318 {
Ed Tanous828c5a62024-02-09 16:59:22 -0800319 std::cerr << "Invalid data length returned\n";
James Feist961bf092020-07-01 16:38:12 -0700320 }
321 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700322 }
James Feist961bf092020-07-01 16:38:12 -0700323 resp = data[3];
324 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700325 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700326 case (ReadingFormat::nineBit):
327 case (ReadingFormat::tenBit):
328 case (ReadingFormat::fifteenBit):
329 {
330 if (data.size() != 2)
331 {
332 if (errCount == 0U)
333 {
334 std::cerr << "Invalid data length returned\n";
335 }
336 return false;
337 }
338
339 // From the Altra Family SoC BMC Interface Specification:
340 // 0xFFFF – This sensor data is either missing or is not supported
341 // by the device.
342 if ((data[0] == 0xff) && (data[1] == 0xff))
343 {
344 return false;
345 }
346
347 if (readingFormat == ReadingFormat::nineBit)
348 {
349 int16_t value = data[0];
350 if ((data[1] & 0x1) != 0)
351 {
352 // Sign extend to 16 bits
353 value |= 0xFF00;
354 }
355 resp = value;
356 }
357 else if (readingFormat == ReadingFormat::tenBit)
358 {
359 uint16_t value = ((data[1] & 0x3) << 8) + data[0];
360 resp = value;
361 }
362 else if (readingFormat == ReadingFormat::fifteenBit)
363 {
364 uint16_t value = ((data[1] & 0x7F) << 8) + data[0];
365 // Convert mV to V
366 resp = value / 1000.0;
367 }
368
369 return true;
370 }
James Feistd7ae29a2020-06-25 15:42:46 -0700371 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700372 {
James Feistd7ae29a2020-06-25 15:42:46 -0700373 if (data.size() < 5)
374 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700375 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700376 {
Ed Tanous828c5a62024-02-09 16:59:22 -0800377 std::cerr << "Invalid data length returned\n";
James Feist961bf092020-07-01 16:38:12 -0700378 }
379 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700380 }
381
James Feiste4a970d2020-08-19 11:21:58 -0700382 int16_t value = ((data[4] << 8) | data[3]);
James Feiste4a970d2020-08-19 11:21:58 -0700383 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700384 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700385 }
James Feistd7ae29a2020-06-25 15:42:46 -0700386 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700387 {
James Feistd7ae29a2020-06-25 15:42:46 -0700388 if (data.size() < 5)
389 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700390 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700391 {
Ed Tanous828c5a62024-02-09 16:59:22 -0800392 std::cerr << "Invalid data length returned\n";
James Feist961bf092020-07-01 16:38:12 -0700393 }
394 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700395 }
396
James Feist961bf092020-07-01 16:38:12 -0700397 resp = ((data[4] << 8) | data[3]) >> 3;
398 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700399 }
Jayashree-D37322572021-03-19 17:40:56 +0530400 case (ReadingFormat::linearElevenBit):
401 {
402 if (data.size() < 5)
403 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700404 if (errCount == 0U)
Jayashree-D37322572021-03-19 17:40:56 +0530405 {
Ed Tanous828c5a62024-02-09 16:59:22 -0800406 std::cerr << "Invalid data length returned\n";
Jayashree-D37322572021-03-19 17:40:56 +0530407 }
408 return false;
409 }
410
411 int16_t value = ((data[4] << 8) | data[3]);
412 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
413 value <<= shift;
414 value >>= shift;
415 resp = value;
416 return true;
417 }
James Feistd7ae29a2020-06-25 15:42:46 -0700418 default:
419 throw std::runtime_error("Invalid reading type");
420 }
421}
422
Vikash Chandola1f847972022-09-28 09:47:32 +0000423void IpmbSensor::ipmbRequestCompletionCb(const boost::system::error_code& ec,
424 const IpmbMethodType& response)
425{
426 const int& status = std::get<0>(response);
427 if (ec || (status != 0))
428 {
429 incrementError();
430 read();
431 return;
432 }
433 const std::vector<uint8_t>& data = std::get<5>(response);
434 if constexpr (debug)
435 {
436 std::cout << name << ": ";
437 for (size_t d : data)
438 {
439 std::cout << d << " ";
440 }
441 std::cout << "\n";
442 }
443 if (data.empty())
444 {
445 incrementError();
446 read();
447 return;
448 }
449
450 double value = 0;
451
Ed Tanous828c5a62024-02-09 16:59:22 -0800452 if (!processReading(readingFormat, command, data, value, errCount))
Vikash Chandola1f847972022-09-28 09:47:32 +0000453 {
454 incrementError();
455 read();
456 return;
457 }
458
459 // rawValue only used in debug logging
460 // up to 5th byte in data are used to derive value
461 size_t end = std::min(sizeof(uint64_t), data.size());
462 uint64_t rawData = 0;
463 for (size_t i = 0; i < end; i++)
464 {
465 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
466 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
467 }
468 rawValue = static_cast<double>(rawData);
469
470 /* Adjust value as per scale and offset */
471 value = (value * scaleVal) + offsetVal;
472 updateValue(value);
473 read();
474}
475
Ed Tanous201a1012024-04-03 18:07:28 -0700476void IpmbSensor::read()
James Feist6ef20402019-01-07 16:45:08 -0800477{
Ed Tanous83db50c2023-03-01 10:20:24 -0800478 waitTimer.expires_after(std::chrono::milliseconds(sensorPollMs));
Vikash Chandola1f847972022-09-28 09:47:32 +0000479 waitTimer.async_wait(
480 [weakRef{weak_from_this()}](const boost::system::error_code& ec) {
James Feist6ef20402019-01-07 16:45:08 -0800481 if (ec == boost::asio::error::operation_aborted)
482 {
483 return; // we're being canceled
484 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000485 std::shared_ptr<IpmbSensor> self = weakRef.lock();
486 if (!self)
James Feist6ef20402019-01-07 16:45:08 -0800487 {
James Feist6ef20402019-01-07 16:45:08 -0800488 return;
489 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000490 self->sendIpmbRequest();
James Feist6ef20402019-01-07 16:45:08 -0800491 });
492}
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530493
Vikash Chandola1f847972022-09-28 09:47:32 +0000494void IpmbSensor::sendIpmbRequest()
495{
496 if (!readingStateGood())
497 {
498 updateValue(std::numeric_limits<double>::quiet_NaN());
499 read();
500 return;
501 }
502 dbusConnection->async_method_call(
503 [weakRef{weak_from_this()}](boost::system::error_code ec,
504 const IpmbMethodType& response) {
505 std::shared_ptr<IpmbSensor> self = weakRef.lock();
506 if (!self)
507 {
508 return;
509 }
510 self->ipmbRequestCompletionCb(ec, response);
Patrick Williams597e8422023-10-20 11:19:01 -0500511 },
Vikash Chandola1f847972022-09-28 09:47:32 +0000512 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
513 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
514 "sendRequest", commandAddress, netfn, lun, command, commandData);
515}
516
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530517bool IpmbSensor::sensorClassType(const std::string& sensorClass)
518{
519 if (sensorClass == "PxeBridgeTemp")
520 {
521 type = IpmbType::PXE1410CVR;
522 }
523 else if (sensorClass == "IRBridgeTemp")
524 {
525 type = IpmbType::IR38363VR;
526 }
527 else if (sensorClass == "HSCBridge")
528 {
529 type = IpmbType::ADM1278HSC;
530 }
531 else if (sensorClass == "MpsBridgeTemp")
532 {
533 type = IpmbType::mpsVR;
534 }
535 else if (sensorClass == "METemp" || sensorClass == "MESensor")
536 {
537 type = IpmbType::meSensor;
538 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700539 else if (sensorClass == "SMPro")
540 {
541 type = IpmbType::SMPro;
542 }
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530543 else
544 {
545 std::cerr << "Invalid class " << sensorClass << "\n";
546 return false;
547 }
548 return true;
549}
550
551void IpmbSensor::sensorSubType(const std::string& sensorTypeName)
552{
553 if (sensorTypeName == "voltage")
554 {
555 subType = IpmbSubType::volt;
556 }
557 else if (sensorTypeName == "power")
558 {
559 subType = IpmbSubType::power;
560 }
561 else if (sensorTypeName == "current")
562 {
563 subType = IpmbSubType::curr;
564 }
565 else if (sensorTypeName == "utilization")
566 {
567 subType = IpmbSubType::util;
568 }
569 else
570 {
571 subType = IpmbSubType::temp;
572 }
573}
574
575void IpmbSensor::parseConfigValues(const SensorBaseConfigMap& entry)
576{
577 auto findScaleVal = entry.find("ScaleValue");
578 if (findScaleVal != entry.end())
579 {
580 scaleVal = std::visit(VariantToDoubleVisitor(), findScaleVal->second);
581 }
582
583 auto findOffsetVal = entry.find("OffsetValue");
584 if (findOffsetVal != entry.end())
585 {
586 offsetVal = std::visit(VariantToDoubleVisitor(), findOffsetVal->second);
587 }
588
Zev Weissa4d27682022-07-19 15:30:36 -0700589 readState = getPowerState(entry);
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530590}
591
James Feist6ef20402019-01-07 16:45:08 -0800592void createSensors(
Ed Tanous1f978632023-02-28 18:16:39 -0800593 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
Vikash Chandola1f847972022-09-28 09:47:32 +0000594 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
James Feist6ef20402019-01-07 16:45:08 -0800595 sensors,
596 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
597{
598 if (!dbusConnection)
599 {
600 std::cerr << "Connection not created\n";
601 return;
602 }
603 dbusConnection->async_method_call(
604 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
Ed Tanousbb679322022-05-16 16:10:00 -0700605 if (ec)
606 {
607 std::cerr << "Error contacting entity manager\n";
608 return;
609 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700610 for (const auto& [path, interfaces] : resp)
Ed Tanousbb679322022-05-16 16:10:00 -0700611 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700612 for (const auto& [intf, cfg] : interfaces)
James Feist6ef20402019-01-07 16:45:08 -0800613 {
Zev Weiss054aad82022-08-18 01:37:34 -0700614 if (intf != configInterfaceName(sensorType))
James Feist6ef20402019-01-07 16:45:08 -0800615 {
Ed Tanousbb679322022-05-16 16:10:00 -0700616 continue;
James Feist6ef20402019-01-07 16:45:08 -0800617 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700618 std::string name = loadVariant<std::string>(cfg, "Name");
Ed Tanousbb679322022-05-16 16:10:00 -0700619
620 std::vector<thresholds::Threshold> sensorThresholds;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700621 if (!parseThresholdsFromConfig(interfaces, sensorThresholds))
Ed Tanousbb679322022-05-16 16:10:00 -0700622 {
Ed Tanous828c5a62024-02-09 16:59:22 -0800623 std::cerr << "error populating thresholds " << name << "\n";
Ed Tanousbb679322022-05-16 16:10:00 -0700624 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700625 uint8_t deviceAddress = loadVariant<uint8_t>(cfg, "Address");
Ed Tanousbb679322022-05-16 16:10:00 -0700626
Patrick Williams779c96a2023-05-10 07:50:42 -0500627 std::string sensorClass = loadVariant<std::string>(cfg,
628 "Class");
Ed Tanousbb679322022-05-16 16:10:00 -0700629
630 uint8_t hostSMbusIndex = hostSMbusIndexDefault;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700631 auto findSmType = cfg.find("HostSMbusIndex");
632 if (findSmType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700633 {
634 hostSMbusIndex = std::visit(VariantToUnsignedIntVisitor(),
635 findSmType->second);
636 }
637
Zev Weiss8569bf22022-10-11 15:37:44 -0700638 float pollRate = getPollRate(cfg, pollRateDefault);
Ed Tanousbb679322022-05-16 16:10:00 -0700639
Jayashree Dhanapal6ee62942021-12-14 15:22:23 +0530640 uint8_t ipmbBusIndex = ipmbBusIndexDefault;
641 auto findBusType = cfg.find("Bus");
642 if (findBusType != cfg.end())
643 {
644 ipmbBusIndex = std::visit(VariantToUnsignedIntVisitor(),
645 findBusType->second);
646 std::cerr << "Ipmb Bus Index for " << name << " is "
647 << static_cast<int>(ipmbBusIndex) << "\n";
648 }
649
Ed Tanousbb679322022-05-16 16:10:00 -0700650 /* Default sensor type is "temperature" */
651 std::string sensorTypeName = "temperature";
Zev Weiss8ba551b2022-08-12 18:21:02 -0700652 auto findType = cfg.find("SensorType");
653 if (findType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700654 {
Patrick Williams779c96a2023-05-10 07:50:42 -0500655 sensorTypeName = std::visit(VariantToStringVisitor(),
656 findType->second);
Ed Tanousbb679322022-05-16 16:10:00 -0700657 }
658
659 auto& sensor = sensors[name];
Vikash Chandola1f847972022-09-28 09:47:32 +0000660 sensor = nullptr;
661 sensor = std::make_shared<IpmbSensor>(
Zev Weiss8ba551b2022-08-12 18:21:02 -0700662 dbusConnection, io, name, path, objectServer,
Ed Tanousbb679322022-05-16 16:10:00 -0700663 std::move(sensorThresholds), deviceAddress, hostSMbusIndex,
664 pollRate, sensorTypeName);
665
Zev Weiss8ba551b2022-08-12 18:21:02 -0700666 sensor->parseConfigValues(cfg);
Ed Tanousbb679322022-05-16 16:10:00 -0700667 if (!(sensor->sensorClassType(sensorClass)))
668 {
669 continue;
670 }
671 sensor->sensorSubType(sensorTypeName);
672 sensor->init();
James Feist6ef20402019-01-07 16:45:08 -0800673 }
Ed Tanousbb679322022-05-16 16:10:00 -0700674 }
Patrick Williams597e8422023-10-20 11:19:01 -0500675 },
JeffLin2c5a1f22022-10-05 15:19:09 +0800676 entityManagerName, "/xyz/openbmc_project/inventory",
677 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6ef20402019-01-07 16:45:08 -0800678}
679
Kumar Thangavel5d032bc2022-11-30 20:24:47 +0530680void interfaceRemoved(
681 sdbusplus::message_t& message,
682 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
683 sensors)
684{
685 if (message.is_method_error())
686 {
687 std::cerr << "interfacesRemoved callback method error\n";
688 return;
689 }
690
691 sdbusplus::message::object_path removedPath;
692 std::vector<std::string> interfaces;
693
694 message.read(removedPath, interfaces);
695
696 // If the xyz.openbmc_project.Confguration.X interface was removed
697 // for one or more sensors, delete those sensor objects.
698 auto sensorIt = sensors.begin();
699 while (sensorIt != sensors.end())
700 {
701 if ((sensorIt->second->configurationPath == removedPath) &&
702 (std::find(interfaces.begin(), interfaces.end(),
703 configInterfaceName(sdrInterface)) != interfaces.end()))
704 {
705 sensorIt = sensors.erase(sensorIt);
706 }
707 else
708 {
709 sensorIt++;
710 }
711 }
712}