blob: fc6cc7a6e8cd318a62e371a964624a525c96051b [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
Patrick Williams2aaf7172024-08-16 15:20:40 -040063IpmbSensor::IpmbSensor(
64 std::shared_ptr<sdbusplus::asio::connection>& conn,
65 boost::asio::io_context& io, const std::string& sensorName,
66 const std::string& sensorConfiguration,
67 sdbusplus::asio::object_server& objectServer,
68 std::vector<thresholds::Threshold>&& thresholdData, uint8_t deviceAddress,
69 uint8_t hostSMbusIndex, const float pollRate, std::string& sensorTypeName) :
Zhikui Renda98f092021-11-01 09:41:08 -070070 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -070071 sensorConfiguration, "IpmbSensor", false, false, ipmbMaxReading,
72 ipmbMinReading, conn, PowerState::on),
Anoop S832a2c62020-11-20 19:21:22 +000073 deviceAddress(deviceAddress), hostSMbusIndex(hostSMbusIndex),
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053074 sensorPollMs(static_cast<int>(pollRate * 1000)), objectServer(objectServer),
75 waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080076{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070077 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
78
James Feist6ef20402019-01-07 16:45:08 -080079 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070080 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080081
Jayashree Dhanapal56678082022-01-04 17:27:20 +053082 for (const auto& threshold : thresholds)
James Feist6ef20402019-01-07 16:45:08 -080083 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053084 std::string interface = thresholds::getInterface(threshold.level);
85 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
86 objectServer.add_interface(dbusPath, interface);
James Feist6ef20402019-01-07 16:45:08 -080087 }
James Feist2adc95c2019-09-30 14:55:28 -070088 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -080089}
90
91IpmbSensor::~IpmbSensor()
92{
93 waitTimer.cancel();
Jayashree Dhanapal56678082022-01-04 17:27:20 +053094 for (const auto& iface : thresholdInterfaces)
95 {
96 objectServer.remove_interface(iface);
97 }
James Feist6ef20402019-01-07 16:45:08 -080098 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -080099 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -0800100}
101
Ed Tanous201a1012024-04-03 18:07:28 -0700102std::string IpmbSensor::getSubTypeUnits() const
Zev Weiss6b6891c2021-04-22 02:46:21 -0500103{
104 switch (subType)
105 {
106 case IpmbSubType::temp:
107 return sensor_paths::unitDegreesC;
108 case IpmbSubType::curr:
109 return sensor_paths::unitAmperes;
110 case IpmbSubType::power:
111 return sensor_paths::unitWatts;
112 case IpmbSubType::volt:
113 return sensor_paths::unitVolts;
114 case IpmbSubType::util:
115 return sensor_paths::unitPercent;
116 default:
117 throw std::runtime_error("Invalid sensor type");
118 }
119}
120
Ed Tanous201a1012024-04-03 18:07:28 -0700121void IpmbSensor::init()
James Feist6ef20402019-01-07 16:45:08 -0800122{
James Feist6ef20402019-01-07 16:45:08 -0800123 loadDefaults();
Andrei Kartashev39287412022-02-04 16:04:47 +0300124 setInitialProperties(getSubTypeUnits());
James Feist6ef20402019-01-07 16:45:08 -0800125 if (initCommand)
126 {
James Feistf7e2c5d2019-02-13 17:27:51 -0800127 runInitCmd();
128 }
129 read();
130}
131
Vikash Chandola1f847972022-09-28 09:47:32 +0000132static void initCmdCb(const std::weak_ptr<IpmbSensor>& weakRef,
133 const boost::system::error_code& ec,
134 const IpmbMethodType& response)
135{
136 std::shared_ptr<IpmbSensor> self = weakRef.lock();
137 if (!self)
138 {
139 return;
140 }
141 const int& status = std::get<0>(response);
142 if (ec || (status != 0))
143 {
144 std::cerr << "Error setting init command for device: " << self->name
145 << "\n";
146 }
147}
148
James Feistf7e2c5d2019-02-13 17:27:51 -0800149void IpmbSensor::runInitCmd()
150{
Vikash Chandola1f847972022-09-28 09:47:32 +0000151 if (!initCommand)
James Feistf7e2c5d2019-02-13 17:27:51 -0800152 {
Vikash Chandola1f847972022-09-28 09:47:32 +0000153 return;
James Feist6ef20402019-01-07 16:45:08 -0800154 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000155 dbusConnection->async_method_call(
156 [weakRef{weak_from_this()}](const boost::system::error_code& ec,
157 const IpmbMethodType& response) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400158 initCmdCb(weakRef, ec, response);
159 },
Vikash Chandola1f847972022-09-28 09:47:32 +0000160 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
161 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
162 "sendRequest", commandAddress, netfn, lun, *initCommand, initData);
James Feist6ef20402019-01-07 16:45:08 -0800163}
164
165void IpmbSensor::loadDefaults()
166{
167 if (type == IpmbType::meSensor)
168 {
169 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200170 netfn = ipmi::sensor::netFn;
171 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800172 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700173 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800174 }
175 else if (type == IpmbType::PXE1410CVR)
176 {
177 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200178 netfn = ipmi::me_bridge::netFn;
179 command = ipmi::me_bridge::sendRawPmbus;
180 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700181 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000182 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
183 deviceAddress, 0x00, 0x00, 0x00, 0x00,
184 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700185 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000186 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
187 deviceAddress, 0x00, 0x00, 0x00, 0x00,
188 0x02, 0x00, 0x00, 0x00};
Jayashree-D37322572021-03-19 17:40:56 +0530189 readingFormat = ReadingFormat::linearElevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800190 }
191 else if (type == IpmbType::IR38363VR)
192 {
193 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200194 netfn = ipmi::me_bridge::netFn;
195 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700196 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000197 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
198 deviceAddress, 00, 0x00, 0x00, 0x00,
199 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700200 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800201 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700202 else if (type == IpmbType::ADM1278HSC)
203 {
204 commandAddress = meAddress;
Ed Tanousa771f6a2022-01-14 09:36:51 -0800205 uint8_t snsNum = 0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700206 switch (subType)
207 {
208 case IpmbSubType::temp:
209 case IpmbSubType::curr:
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700210 if (subType == IpmbSubType::temp)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700211 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700212 snsNum = 0x8d;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700213 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700214 else
Ed Tanous8a57ec02020-10-09 12:46:52 -0700215 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700216 snsNum = 0x8c;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700217 }
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200218 netfn = ipmi::me_bridge::netFn;
219 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700220 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
221 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700222 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700223 break;
224 case IpmbSubType::power:
225 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200226 netfn = ipmi::sensor::netFn;
227 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700228 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700229 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700230 break;
231 default:
232 throw std::runtime_error("Invalid sensor type");
233 }
234 }
James Feist6ef20402019-01-07 16:45:08 -0800235 else if (type == IpmbType::mpsVR)
236 {
237 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200238 netfn = ipmi::me_bridge::netFn;
239 command = ipmi::me_bridge::sendRawPmbus;
240 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700241 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000242 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
243 deviceAddress, 0x00, 0x00, 0x00, 0x00,
244 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700245 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000246 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
247 deviceAddress, 0x00, 0x00, 0x00, 0x00,
248 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700249 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800250 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700251 else if (type == IpmbType::SMPro)
252 {
253 // This is an Ampere SMPro reachable via a BMC. For example,
254 // this architecture is used on ADLINK Ampere Altra systems.
255 // See the Ampere Family SoC BMC Interface Specification at
256 // https://amperecomputing.com/customer-connect/products/altra-family-software---firmware
257 // for details of the sensors.
258 commandAddress = 0;
259 netfn = 0x30;
260 command = 0x31;
261 commandData = {0x9e, deviceAddress};
262 switch (subType)
263 {
264 case IpmbSubType::temp:
265 readingFormat = ReadingFormat::nineBit;
266 break;
267 case IpmbSubType::power:
268 readingFormat = ReadingFormat::tenBit;
269 break;
270 case IpmbSubType::curr:
271 case IpmbSubType::volt:
272 readingFormat = ReadingFormat::fifteenBit;
273 break;
274 default:
275 throw std::runtime_error("Invalid sensor type");
276 }
277 }
James Feist6ef20402019-01-07 16:45:08 -0800278 else
279 {
280 throw std::runtime_error("Invalid sensor type");
281 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200282
283 if (subType == IpmbSubType::util)
284 {
285 // Utilization need to be scaled to percent
286 maxValue = 100;
287 minValue = 0;
288 }
James Feist6ef20402019-01-07 16:45:08 -0800289}
290
Ed Tanous201a1012024-04-03 18:07:28 -0700291void IpmbSensor::checkThresholds()
James Feist6ef20402019-01-07 16:45:08 -0800292{
James Feist6ef20402019-01-07 16:45:08 -0800293 thresholds::checkThresholds(this);
294}
295
Ed Tanous828c5a62024-02-09 16:59:22 -0800296bool IpmbSensor::processReading(ReadingFormat readingFormat, uint8_t command,
297 const std::vector<uint8_t>& data, double& resp,
298 size_t errCount)
James Feistd7ae29a2020-06-25 15:42:46 -0700299{
James Feistd7ae29a2020-06-25 15:42:46 -0700300 switch (readingFormat)
301 {
302 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700303 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200304 if (command == ipmi::sensor::getSensorReading &&
305 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700306 {
307 return false;
308 }
James Feist961bf092020-07-01 16:38:12 -0700309 resp = data[0];
310 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700311 }
James Feistd7ae29a2020-06-25 15:42:46 -0700312 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700313 {
James Feistd7ae29a2020-06-25 15:42:46 -0700314 if (data.size() < 4)
315 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700316 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700317 {
Ed Tanous828c5a62024-02-09 16:59:22 -0800318 std::cerr << "Invalid data length returned\n";
James Feist961bf092020-07-01 16:38:12 -0700319 }
320 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700321 }
James Feist961bf092020-07-01 16:38:12 -0700322 resp = data[3];
323 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700324 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700325 case (ReadingFormat::nineBit):
326 case (ReadingFormat::tenBit):
327 case (ReadingFormat::fifteenBit):
328 {
329 if (data.size() != 2)
330 {
331 if (errCount == 0U)
332 {
333 std::cerr << "Invalid data length returned\n";
334 }
335 return false;
336 }
337
338 // From the Altra Family SoC BMC Interface Specification:
339 // 0xFFFF – This sensor data is either missing or is not supported
340 // by the device.
341 if ((data[0] == 0xff) && (data[1] == 0xff))
342 {
343 return false;
344 }
345
346 if (readingFormat == ReadingFormat::nineBit)
347 {
348 int16_t value = data[0];
349 if ((data[1] & 0x1) != 0)
350 {
351 // Sign extend to 16 bits
352 value |= 0xFF00;
353 }
354 resp = value;
355 }
356 else if (readingFormat == ReadingFormat::tenBit)
357 {
358 uint16_t value = ((data[1] & 0x3) << 8) + data[0];
359 resp = value;
360 }
361 else if (readingFormat == ReadingFormat::fifteenBit)
362 {
363 uint16_t value = ((data[1] & 0x7F) << 8) + data[0];
364 // Convert mV to V
365 resp = value / 1000.0;
366 }
367
368 return true;
369 }
James Feistd7ae29a2020-06-25 15:42:46 -0700370 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700371 {
James Feistd7ae29a2020-06-25 15:42:46 -0700372 if (data.size() < 5)
373 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700374 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700375 {
Ed Tanous828c5a62024-02-09 16:59:22 -0800376 std::cerr << "Invalid data length returned\n";
James Feist961bf092020-07-01 16:38:12 -0700377 }
378 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700379 }
380
James Feiste4a970d2020-08-19 11:21:58 -0700381 int16_t value = ((data[4] << 8) | data[3]);
James Feiste4a970d2020-08-19 11:21:58 -0700382 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700383 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700384 }
James Feistd7ae29a2020-06-25 15:42:46 -0700385 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700386 {
James Feistd7ae29a2020-06-25 15:42:46 -0700387 if (data.size() < 5)
388 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700389 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700390 {
Ed Tanous828c5a62024-02-09 16:59:22 -0800391 std::cerr << "Invalid data length returned\n";
James Feist961bf092020-07-01 16:38:12 -0700392 }
393 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700394 }
395
James Feist961bf092020-07-01 16:38:12 -0700396 resp = ((data[4] << 8) | data[3]) >> 3;
397 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700398 }
Jayashree-D37322572021-03-19 17:40:56 +0530399 case (ReadingFormat::linearElevenBit):
400 {
401 if (data.size() < 5)
402 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700403 if (errCount == 0U)
Jayashree-D37322572021-03-19 17:40:56 +0530404 {
Ed Tanous828c5a62024-02-09 16:59:22 -0800405 std::cerr << "Invalid data length returned\n";
Jayashree-D37322572021-03-19 17:40:56 +0530406 }
407 return false;
408 }
409
410 int16_t value = ((data[4] << 8) | data[3]);
411 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
412 value <<= shift;
413 value >>= shift;
414 resp = value;
415 return true;
416 }
James Feistd7ae29a2020-06-25 15:42:46 -0700417 default:
418 throw std::runtime_error("Invalid reading type");
419 }
420}
421
Vikash Chandola1f847972022-09-28 09:47:32 +0000422void IpmbSensor::ipmbRequestCompletionCb(const boost::system::error_code& ec,
423 const IpmbMethodType& response)
424{
425 const int& status = std::get<0>(response);
426 if (ec || (status != 0))
427 {
428 incrementError();
429 read();
430 return;
431 }
432 const std::vector<uint8_t>& data = std::get<5>(response);
433 if constexpr (debug)
434 {
435 std::cout << name << ": ";
436 for (size_t d : data)
437 {
438 std::cout << d << " ";
439 }
440 std::cout << "\n";
441 }
442 if (data.empty())
443 {
444 incrementError();
445 read();
446 return;
447 }
448
449 double value = 0;
450
Ed Tanous828c5a62024-02-09 16:59:22 -0800451 if (!processReading(readingFormat, command, data, value, errCount))
Vikash Chandola1f847972022-09-28 09:47:32 +0000452 {
453 incrementError();
454 read();
455 return;
456 }
457
458 // rawValue only used in debug logging
459 // up to 5th byte in data are used to derive value
460 size_t end = std::min(sizeof(uint64_t), data.size());
461 uint64_t rawData = 0;
462 for (size_t i = 0; i < end; i++)
463 {
464 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
465 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
466 }
467 rawValue = static_cast<double>(rawData);
468
469 /* Adjust value as per scale and offset */
470 value = (value * scaleVal) + offsetVal;
471 updateValue(value);
472 read();
473}
474
Ed Tanous201a1012024-04-03 18:07:28 -0700475void IpmbSensor::read()
James Feist6ef20402019-01-07 16:45:08 -0800476{
Ed Tanous83db50c2023-03-01 10:20:24 -0800477 waitTimer.expires_after(std::chrono::milliseconds(sensorPollMs));
Vikash Chandola1f847972022-09-28 09:47:32 +0000478 waitTimer.async_wait(
479 [weakRef{weak_from_this()}](const boost::system::error_code& ec) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400480 if (ec == boost::asio::error::operation_aborted)
481 {
482 return; // we're being canceled
483 }
484 std::shared_ptr<IpmbSensor> self = weakRef.lock();
485 if (!self)
486 {
487 return;
488 }
489 self->sendIpmbRequest();
490 });
James Feist6ef20402019-01-07 16:45:08 -0800491}
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530492
Vikash Chandola1f847972022-09-28 09:47:32 +0000493void IpmbSensor::sendIpmbRequest()
494{
495 if (!readingStateGood())
496 {
497 updateValue(std::numeric_limits<double>::quiet_NaN());
498 read();
499 return;
500 }
501 dbusConnection->async_method_call(
502 [weakRef{weak_from_this()}](boost::system::error_code ec,
503 const IpmbMethodType& response) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400504 std::shared_ptr<IpmbSensor> self = weakRef.lock();
505 if (!self)
506 {
507 return;
508 }
509 self->ipmbRequestCompletionCb(ec, response);
510 },
Vikash Chandola1f847972022-09-28 09:47:32 +0000511 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
512 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
513 "sendRequest", commandAddress, netfn, lun, command, commandData);
514}
515
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530516bool IpmbSensor::sensorClassType(const std::string& sensorClass)
517{
518 if (sensorClass == "PxeBridgeTemp")
519 {
520 type = IpmbType::PXE1410CVR;
521 }
522 else if (sensorClass == "IRBridgeTemp")
523 {
524 type = IpmbType::IR38363VR;
525 }
526 else if (sensorClass == "HSCBridge")
527 {
528 type = IpmbType::ADM1278HSC;
529 }
530 else if (sensorClass == "MpsBridgeTemp")
531 {
532 type = IpmbType::mpsVR;
533 }
534 else if (sensorClass == "METemp" || sensorClass == "MESensor")
535 {
536 type = IpmbType::meSensor;
537 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700538 else if (sensorClass == "SMPro")
539 {
540 type = IpmbType::SMPro;
541 }
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530542 else
543 {
544 std::cerr << "Invalid class " << sensorClass << "\n";
545 return false;
546 }
547 return true;
548}
549
550void IpmbSensor::sensorSubType(const std::string& sensorTypeName)
551{
552 if (sensorTypeName == "voltage")
553 {
554 subType = IpmbSubType::volt;
555 }
556 else if (sensorTypeName == "power")
557 {
558 subType = IpmbSubType::power;
559 }
560 else if (sensorTypeName == "current")
561 {
562 subType = IpmbSubType::curr;
563 }
564 else if (sensorTypeName == "utilization")
565 {
566 subType = IpmbSubType::util;
567 }
568 else
569 {
570 subType = IpmbSubType::temp;
571 }
572}
573
574void IpmbSensor::parseConfigValues(const SensorBaseConfigMap& entry)
575{
576 auto findScaleVal = entry.find("ScaleValue");
577 if (findScaleVal != entry.end())
578 {
579 scaleVal = std::visit(VariantToDoubleVisitor(), findScaleVal->second);
580 }
581
582 auto findOffsetVal = entry.find("OffsetValue");
583 if (findOffsetVal != entry.end())
584 {
585 offsetVal = std::visit(VariantToDoubleVisitor(), findOffsetVal->second);
586 }
587
Zev Weissa4d27682022-07-19 15:30:36 -0700588 readState = getPowerState(entry);
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530589}
590
James Feist6ef20402019-01-07 16:45:08 -0800591void createSensors(
Ed Tanous1f978632023-02-28 18:16:39 -0800592 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
Vikash Chandola1f847972022-09-28 09:47:32 +0000593 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
James Feist6ef20402019-01-07 16:45:08 -0800594 sensors,
595 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
596{
597 if (!dbusConnection)
598 {
599 std::cerr << "Connection not created\n";
600 return;
601 }
602 dbusConnection->async_method_call(
603 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400604 if (ec)
James Feist6ef20402019-01-07 16:45:08 -0800605 {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400606 std::cerr << "Error contacting entity manager\n";
607 return;
James Feist6ef20402019-01-07 16:45:08 -0800608 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400609 for (const auto& [path, interfaces] : resp)
610 {
611 for (const auto& [intf, cfg] : interfaces)
612 {
613 if (intf != configInterfaceName(sensorType))
614 {
615 continue;
616 }
617 std::string name = loadVariant<std::string>(cfg, "Name");
618
619 std::vector<thresholds::Threshold> sensorThresholds;
620 if (!parseThresholdsFromConfig(interfaces,
621 sensorThresholds))
622 {
623 std::cerr
624 << "error populating thresholds " << name << "\n";
625 }
626 uint8_t deviceAddress =
627 loadVariant<uint8_t>(cfg, "Address");
628
629 std::string sensorClass =
630 loadVariant<std::string>(cfg, "Class");
631
632 uint8_t hostSMbusIndex = hostSMbusIndexDefault;
633 auto findSmType = cfg.find("HostSMbusIndex");
634 if (findSmType != cfg.end())
635 {
636 hostSMbusIndex = std::visit(
637 VariantToUnsignedIntVisitor(), findSmType->second);
638 }
639
640 float pollRate = getPollRate(cfg, pollRateDefault);
641
642 uint8_t ipmbBusIndex = ipmbBusIndexDefault;
643 auto findBusType = cfg.find("Bus");
644 if (findBusType != cfg.end())
645 {
646 ipmbBusIndex = std::visit(VariantToUnsignedIntVisitor(),
647 findBusType->second);
648 std::cerr << "Ipmb Bus Index for " << name << " is "
649 << static_cast<int>(ipmbBusIndex) << "\n";
650 }
651
652 /* Default sensor type is "temperature" */
653 std::string sensorTypeName = "temperature";
654 auto findType = cfg.find("SensorType");
655 if (findType != cfg.end())
656 {
657 sensorTypeName = std::visit(VariantToStringVisitor(),
658 findType->second);
659 }
660
661 auto& sensor = sensors[name];
662 sensor = nullptr;
663 sensor = std::make_shared<IpmbSensor>(
664 dbusConnection, io, name, path, objectServer,
665 std::move(sensorThresholds), deviceAddress,
666 hostSMbusIndex, pollRate, sensorTypeName);
667
668 sensor->parseConfigValues(cfg);
669 if (!(sensor->sensorClassType(sensorClass)))
670 {
671 continue;
672 }
673 sensor->sensorSubType(sensorTypeName);
674 sensor->init();
675 }
676 }
677 },
JeffLin2c5a1f22022-10-05 15:19:09 +0800678 entityManagerName, "/xyz/openbmc_project/inventory",
679 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6ef20402019-01-07 16:45:08 -0800680}
681
Kumar Thangavel5d032bc2022-11-30 20:24:47 +0530682void interfaceRemoved(
683 sdbusplus::message_t& message,
684 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
685 sensors)
686{
687 if (message.is_method_error())
688 {
689 std::cerr << "interfacesRemoved callback method error\n";
690 return;
691 }
692
693 sdbusplus::message::object_path removedPath;
694 std::vector<std::string> interfaces;
695
696 message.read(removedPath, interfaces);
697
698 // If the xyz.openbmc_project.Confguration.X interface was removed
699 // for one or more sensors, delete those sensor objects.
700 auto sensorIt = sensors.begin();
701 while (sensorIt != sensors.end())
702 {
703 if ((sensorIt->second->configurationPath == removedPath) &&
704 (std::find(interfaces.begin(), interfaces.end(),
705 configInterfaceName(sdrInterface)) != interfaces.end()))
706 {
707 sensorIt = sensors.erase(sensorIt);
708 }
709 else
710 {
711 sensorIt++;
712 }
713 }
714}