blob: 5b4649bdd99560aec44f7282a91b56cf5f05c1d9 [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>
28#include <boost/asio/post.hpp>
29#include <boost/asio/steady_timer.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070030#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070031#include <sdbusplus/asio/connection.hpp>
32#include <sdbusplus/asio/object_server.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070033#include <sdbusplus/bus.hpp>
James Feist38fb5982020-05-28 10:09:54 -070034#include <sdbusplus/bus/match.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070035#include <sdbusplus/message.hpp>
36#include <sdbusplus/message/native_types.hpp>
James Feist38fb5982020-05-28 10:09:54 -070037
Ed Tanouseacbfdd2024-04-04 12:00:24 -070038#include <algorithm>
39#include <array>
James Feist6ef20402019-01-07 16:45:08 -080040#include <chrono>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070041#include <cstddef>
42#include <cstdint>
Patrick Venture96e97db2019-10-31 13:44:38 -070043#include <functional>
James Feist6ef20402019-01-07 16:45:08 -080044#include <iostream>
45#include <limits>
Patrick Venture96e97db2019-10-31 13:44:38 -070046#include <memory>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070047#include <stdexcept>
Patrick Venture96e97db2019-10-31 13:44:38 -070048#include <string>
49#include <tuple>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070050#include <utility>
Patrick Venture96e97db2019-10-31 13:44:38 -070051#include <variant>
James Feist6ef20402019-01-07 16:45:08 -080052#include <vector>
53
54constexpr const bool debug = false;
55
Zev Weiss054aad82022-08-18 01:37:34 -070056constexpr const char* sensorType = "IpmbSensor";
Jayashree Dhanapal3746c552022-03-21 14:45:52 +053057constexpr const char* sdrInterface = "IpmbDevice";
58
James Feist6ef20402019-01-07 16:45:08 -080059static constexpr double ipmbMaxReading = 0xFF;
60static constexpr double ipmbMinReading = 0;
61
62static constexpr uint8_t meAddress = 1;
63static constexpr uint8_t lun = 0;
Anoop S832a2c62020-11-20 19:21:22 +000064static constexpr uint8_t hostSMbusIndexDefault = 0x03;
Jayashree Dhanapal6ee62942021-12-14 15:22:23 +053065static constexpr uint8_t ipmbBusIndexDefault = 0;
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053066static constexpr float pollRateDefault = 1; // in seconds
James Feist6ef20402019-01-07 16:45:08 -080067
Vijay Khemka682a5cb2019-07-18 17:34:03 -070068static constexpr const char* sensorPathPrefix = "/xyz/openbmc_project/sensors/";
69
Vikash Chandola1f847972022-09-28 09:47:32 +000070boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>> sensors;
Jayashree Dhanapal3746c552022-03-21 14:45:52 +053071boost::container::flat_map<uint8_t, std::shared_ptr<IpmbSDRDevice>> sdrsensor;
James Feistf7e2c5d2019-02-13 17:27:51 -080072
Ed Tanous9b4a20e2022-09-06 08:47:11 -070073std::unique_ptr<boost::asio::steady_timer> initCmdTimer;
James Feist0d4f2bd2019-03-05 13:15:40 -080074
James Feist6ef20402019-01-07 16:45:08 -080075IpmbSensor::IpmbSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
Ed Tanous1f978632023-02-28 18:16:39 -080076 boost::asio::io_context& io,
James Feist6ef20402019-01-07 16:45:08 -080077 const std::string& sensorName,
78 const std::string& sensorConfiguration,
79 sdbusplus::asio::object_server& objectServer,
80 std::vector<thresholds::Threshold>&& thresholdData,
Anoop S832a2c62020-11-20 19:21:22 +000081 uint8_t deviceAddress, uint8_t hostSMbusIndex,
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053082 const float pollRate, std::string& sensorTypeName) :
Zhikui Renda98f092021-11-01 09:41:08 -070083 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -070084 sensorConfiguration, "IpmbSensor", false, false, ipmbMaxReading,
85 ipmbMinReading, conn, PowerState::on),
Anoop S832a2c62020-11-20 19:21:22 +000086 deviceAddress(deviceAddress), hostSMbusIndex(hostSMbusIndex),
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053087 sensorPollMs(static_cast<int>(pollRate * 1000)), objectServer(objectServer),
88 waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080089{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070090 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
91
James Feist6ef20402019-01-07 16:45:08 -080092 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070093 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080094
Jayashree Dhanapal56678082022-01-04 17:27:20 +053095 for (const auto& threshold : thresholds)
James Feist6ef20402019-01-07 16:45:08 -080096 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053097 std::string interface = thresholds::getInterface(threshold.level);
98 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
99 objectServer.add_interface(dbusPath, interface);
James Feist6ef20402019-01-07 16:45:08 -0800100 }
James Feist2adc95c2019-09-30 14:55:28 -0700101 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -0800102}
103
104IpmbSensor::~IpmbSensor()
105{
106 waitTimer.cancel();
Jayashree Dhanapal56678082022-01-04 17:27:20 +0530107 for (const auto& iface : thresholdInterfaces)
108 {
109 objectServer.remove_interface(iface);
110 }
James Feist6ef20402019-01-07 16:45:08 -0800111 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800112 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -0800113}
114
Ed Tanous201a1012024-04-03 18:07:28 -0700115std::string IpmbSensor::getSubTypeUnits() const
Zev Weiss6b6891c2021-04-22 02:46:21 -0500116{
117 switch (subType)
118 {
119 case IpmbSubType::temp:
120 return sensor_paths::unitDegreesC;
121 case IpmbSubType::curr:
122 return sensor_paths::unitAmperes;
123 case IpmbSubType::power:
124 return sensor_paths::unitWatts;
125 case IpmbSubType::volt:
126 return sensor_paths::unitVolts;
127 case IpmbSubType::util:
128 return sensor_paths::unitPercent;
129 default:
130 throw std::runtime_error("Invalid sensor type");
131 }
132}
133
Ed Tanous201a1012024-04-03 18:07:28 -0700134void IpmbSensor::init()
James Feist6ef20402019-01-07 16:45:08 -0800135{
James Feist6ef20402019-01-07 16:45:08 -0800136 loadDefaults();
Andrei Kartashev39287412022-02-04 16:04:47 +0300137 setInitialProperties(getSubTypeUnits());
James Feist6ef20402019-01-07 16:45:08 -0800138 if (initCommand)
139 {
James Feistf7e2c5d2019-02-13 17:27:51 -0800140 runInitCmd();
141 }
142 read();
143}
144
Vikash Chandola1f847972022-09-28 09:47:32 +0000145static void initCmdCb(const std::weak_ptr<IpmbSensor>& weakRef,
146 const boost::system::error_code& ec,
147 const IpmbMethodType& response)
148{
149 std::shared_ptr<IpmbSensor> self = weakRef.lock();
150 if (!self)
151 {
152 return;
153 }
154 const int& status = std::get<0>(response);
155 if (ec || (status != 0))
156 {
157 std::cerr << "Error setting init command for device: " << self->name
158 << "\n";
159 }
160}
161
James Feistf7e2c5d2019-02-13 17:27:51 -0800162void IpmbSensor::runInitCmd()
163{
Vikash Chandola1f847972022-09-28 09:47:32 +0000164 if (!initCommand)
James Feistf7e2c5d2019-02-13 17:27:51 -0800165 {
Vikash Chandola1f847972022-09-28 09:47:32 +0000166 return;
James Feist6ef20402019-01-07 16:45:08 -0800167 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000168 dbusConnection->async_method_call(
169 [weakRef{weak_from_this()}](const boost::system::error_code& ec,
170 const IpmbMethodType& response) {
171 initCmdCb(weakRef, ec, response);
Patrick Williams597e8422023-10-20 11:19:01 -0500172 },
Vikash Chandola1f847972022-09-28 09:47:32 +0000173 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
174 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
175 "sendRequest", commandAddress, netfn, lun, *initCommand, initData);
James Feist6ef20402019-01-07 16:45:08 -0800176}
177
178void IpmbSensor::loadDefaults()
179{
180 if (type == IpmbType::meSensor)
181 {
182 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200183 netfn = ipmi::sensor::netFn;
184 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800185 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700186 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800187 }
188 else if (type == IpmbType::PXE1410CVR)
189 {
190 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200191 netfn = ipmi::me_bridge::netFn;
192 command = ipmi::me_bridge::sendRawPmbus;
193 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700194 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000195 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
196 deviceAddress, 0x00, 0x00, 0x00, 0x00,
197 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700198 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000199 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
200 deviceAddress, 0x00, 0x00, 0x00, 0x00,
201 0x02, 0x00, 0x00, 0x00};
Jayashree-D37322572021-03-19 17:40:56 +0530202 readingFormat = ReadingFormat::linearElevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800203 }
204 else if (type == IpmbType::IR38363VR)
205 {
206 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200207 netfn = ipmi::me_bridge::netFn;
208 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700209 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000210 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
211 deviceAddress, 00, 0x00, 0x00, 0x00,
212 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700213 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800214 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700215 else if (type == IpmbType::ADM1278HSC)
216 {
217 commandAddress = meAddress;
Ed Tanousa771f6a2022-01-14 09:36:51 -0800218 uint8_t snsNum = 0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700219 switch (subType)
220 {
221 case IpmbSubType::temp:
222 case IpmbSubType::curr:
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700223 if (subType == IpmbSubType::temp)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700224 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700225 snsNum = 0x8d;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700226 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700227 else
Ed Tanous8a57ec02020-10-09 12:46:52 -0700228 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700229 snsNum = 0x8c;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700230 }
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200231 netfn = ipmi::me_bridge::netFn;
232 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700233 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
234 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700235 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700236 break;
237 case IpmbSubType::power:
238 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200239 netfn = ipmi::sensor::netFn;
240 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700241 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700242 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700243 break;
244 default:
245 throw std::runtime_error("Invalid sensor type");
246 }
247 }
James Feist6ef20402019-01-07 16:45:08 -0800248 else if (type == IpmbType::mpsVR)
249 {
250 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200251 netfn = ipmi::me_bridge::netFn;
252 command = ipmi::me_bridge::sendRawPmbus;
253 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700254 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000255 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
256 deviceAddress, 0x00, 0x00, 0x00, 0x00,
257 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700258 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000259 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
260 deviceAddress, 0x00, 0x00, 0x00, 0x00,
261 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700262 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800263 }
264 else
265 {
266 throw std::runtime_error("Invalid sensor type");
267 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200268
269 if (subType == IpmbSubType::util)
270 {
271 // Utilization need to be scaled to percent
272 maxValue = 100;
273 minValue = 0;
274 }
James Feist6ef20402019-01-07 16:45:08 -0800275}
276
Ed Tanous201a1012024-04-03 18:07:28 -0700277void IpmbSensor::checkThresholds()
James Feist6ef20402019-01-07 16:45:08 -0800278{
James Feist6ef20402019-01-07 16:45:08 -0800279 thresholds::checkThresholds(this);
280}
281
James Feist961bf092020-07-01 16:38:12 -0700282bool IpmbSensor::processReading(const std::vector<uint8_t>& data, double& resp)
James Feistd7ae29a2020-06-25 15:42:46 -0700283{
James Feistd7ae29a2020-06-25 15:42:46 -0700284 switch (readingFormat)
285 {
286 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700287 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200288 if (command == ipmi::sensor::getSensorReading &&
289 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700290 {
291 return false;
292 }
James Feist961bf092020-07-01 16:38:12 -0700293 resp = data[0];
294 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700295 }
James Feistd7ae29a2020-06-25 15:42:46 -0700296 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700297 {
James Feistd7ae29a2020-06-25 15:42:46 -0700298 if (data.size() < 4)
299 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700300 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700301 {
302 std::cerr << "Invalid data length returned for " << name
303 << "\n";
304 }
305 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700306 }
James Feist961bf092020-07-01 16:38:12 -0700307 resp = data[3];
308 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700309 }
James Feistd7ae29a2020-06-25 15:42:46 -0700310 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700311 {
James Feistd7ae29a2020-06-25 15:42:46 -0700312 if (data.size() < 5)
313 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700314 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700315 {
316 std::cerr << "Invalid data length returned for " << name
317 << "\n";
318 }
319 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700320 }
321
James Feiste4a970d2020-08-19 11:21:58 -0700322 int16_t value = ((data[4] << 8) | data[3]);
James Feiste4a970d2020-08-19 11:21:58 -0700323 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700324 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700325 }
James Feistd7ae29a2020-06-25 15:42:46 -0700326 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700327 {
James Feistd7ae29a2020-06-25 15:42:46 -0700328 if (data.size() < 5)
329 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700330 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700331 {
332 std::cerr << "Invalid data length returned for " << name
333 << "\n";
334 }
335 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700336 }
337
James Feist961bf092020-07-01 16:38:12 -0700338 resp = ((data[4] << 8) | data[3]) >> 3;
339 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700340 }
Jayashree-D37322572021-03-19 17:40:56 +0530341 case (ReadingFormat::linearElevenBit):
342 {
343 if (data.size() < 5)
344 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700345 if (errCount == 0U)
Jayashree-D37322572021-03-19 17:40:56 +0530346 {
347 std::cerr << "Invalid data length returned for " << name
348 << "\n";
349 }
350 return false;
351 }
352
353 int16_t value = ((data[4] << 8) | data[3]);
354 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
355 value <<= shift;
356 value >>= shift;
357 resp = value;
358 return true;
359 }
James Feistd7ae29a2020-06-25 15:42:46 -0700360 default:
361 throw std::runtime_error("Invalid reading type");
362 }
363}
364
Vikash Chandola1f847972022-09-28 09:47:32 +0000365void IpmbSensor::ipmbRequestCompletionCb(const boost::system::error_code& ec,
366 const IpmbMethodType& response)
367{
368 const int& status = std::get<0>(response);
369 if (ec || (status != 0))
370 {
371 incrementError();
372 read();
373 return;
374 }
375 const std::vector<uint8_t>& data = std::get<5>(response);
376 if constexpr (debug)
377 {
378 std::cout << name << ": ";
379 for (size_t d : data)
380 {
381 std::cout << d << " ";
382 }
383 std::cout << "\n";
384 }
385 if (data.empty())
386 {
387 incrementError();
388 read();
389 return;
390 }
391
392 double value = 0;
393
394 if (!processReading(data, value))
395 {
396 incrementError();
397 read();
398 return;
399 }
400
401 // rawValue only used in debug logging
402 // up to 5th byte in data are used to derive value
403 size_t end = std::min(sizeof(uint64_t), data.size());
404 uint64_t rawData = 0;
405 for (size_t i = 0; i < end; i++)
406 {
407 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
408 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
409 }
410 rawValue = static_cast<double>(rawData);
411
412 /* Adjust value as per scale and offset */
413 value = (value * scaleVal) + offsetVal;
414 updateValue(value);
415 read();
416}
417
Ed Tanous201a1012024-04-03 18:07:28 -0700418void IpmbSensor::read()
James Feist6ef20402019-01-07 16:45:08 -0800419{
Ed Tanous83db50c2023-03-01 10:20:24 -0800420 waitTimer.expires_after(std::chrono::milliseconds(sensorPollMs));
Vikash Chandola1f847972022-09-28 09:47:32 +0000421 waitTimer.async_wait(
422 [weakRef{weak_from_this()}](const boost::system::error_code& ec) {
James Feist6ef20402019-01-07 16:45:08 -0800423 if (ec == boost::asio::error::operation_aborted)
424 {
425 return; // we're being canceled
426 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000427 std::shared_ptr<IpmbSensor> self = weakRef.lock();
428 if (!self)
James Feist6ef20402019-01-07 16:45:08 -0800429 {
James Feist6ef20402019-01-07 16:45:08 -0800430 return;
431 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000432 self->sendIpmbRequest();
James Feist6ef20402019-01-07 16:45:08 -0800433 });
434}
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530435
Vikash Chandola1f847972022-09-28 09:47:32 +0000436void IpmbSensor::sendIpmbRequest()
437{
438 if (!readingStateGood())
439 {
440 updateValue(std::numeric_limits<double>::quiet_NaN());
441 read();
442 return;
443 }
444 dbusConnection->async_method_call(
445 [weakRef{weak_from_this()}](boost::system::error_code ec,
446 const IpmbMethodType& response) {
447 std::shared_ptr<IpmbSensor> self = weakRef.lock();
448 if (!self)
449 {
450 return;
451 }
452 self->ipmbRequestCompletionCb(ec, response);
Patrick Williams597e8422023-10-20 11:19:01 -0500453 },
Vikash Chandola1f847972022-09-28 09:47:32 +0000454 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
455 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
456 "sendRequest", commandAddress, netfn, lun, command, commandData);
457}
458
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530459bool IpmbSensor::sensorClassType(const std::string& sensorClass)
460{
461 if (sensorClass == "PxeBridgeTemp")
462 {
463 type = IpmbType::PXE1410CVR;
464 }
465 else if (sensorClass == "IRBridgeTemp")
466 {
467 type = IpmbType::IR38363VR;
468 }
469 else if (sensorClass == "HSCBridge")
470 {
471 type = IpmbType::ADM1278HSC;
472 }
473 else if (sensorClass == "MpsBridgeTemp")
474 {
475 type = IpmbType::mpsVR;
476 }
477 else if (sensorClass == "METemp" || sensorClass == "MESensor")
478 {
479 type = IpmbType::meSensor;
480 }
481 else
482 {
483 std::cerr << "Invalid class " << sensorClass << "\n";
484 return false;
485 }
486 return true;
487}
488
489void IpmbSensor::sensorSubType(const std::string& sensorTypeName)
490{
491 if (sensorTypeName == "voltage")
492 {
493 subType = IpmbSubType::volt;
494 }
495 else if (sensorTypeName == "power")
496 {
497 subType = IpmbSubType::power;
498 }
499 else if (sensorTypeName == "current")
500 {
501 subType = IpmbSubType::curr;
502 }
503 else if (sensorTypeName == "utilization")
504 {
505 subType = IpmbSubType::util;
506 }
507 else
508 {
509 subType = IpmbSubType::temp;
510 }
511}
512
513void IpmbSensor::parseConfigValues(const SensorBaseConfigMap& entry)
514{
515 auto findScaleVal = entry.find("ScaleValue");
516 if (findScaleVal != entry.end())
517 {
518 scaleVal = std::visit(VariantToDoubleVisitor(), findScaleVal->second);
519 }
520
521 auto findOffsetVal = entry.find("OffsetValue");
522 if (findOffsetVal != entry.end())
523 {
524 offsetVal = std::visit(VariantToDoubleVisitor(), findOffsetVal->second);
525 }
526
Zev Weissa4d27682022-07-19 15:30:36 -0700527 readState = getPowerState(entry);
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530528}
529
James Feist6ef20402019-01-07 16:45:08 -0800530void createSensors(
Ed Tanous1f978632023-02-28 18:16:39 -0800531 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
Vikash Chandola1f847972022-09-28 09:47:32 +0000532 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
James Feist6ef20402019-01-07 16:45:08 -0800533 sensors,
534 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
535{
536 if (!dbusConnection)
537 {
538 std::cerr << "Connection not created\n";
539 return;
540 }
541 dbusConnection->async_method_call(
542 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
Ed Tanousbb679322022-05-16 16:10:00 -0700543 if (ec)
544 {
545 std::cerr << "Error contacting entity manager\n";
546 return;
547 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700548 for (const auto& [path, interfaces] : resp)
Ed Tanousbb679322022-05-16 16:10:00 -0700549 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700550 for (const auto& [intf, cfg] : interfaces)
James Feist6ef20402019-01-07 16:45:08 -0800551 {
Zev Weiss054aad82022-08-18 01:37:34 -0700552 if (intf != configInterfaceName(sensorType))
James Feist6ef20402019-01-07 16:45:08 -0800553 {
Ed Tanousbb679322022-05-16 16:10:00 -0700554 continue;
James Feist6ef20402019-01-07 16:45:08 -0800555 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700556 std::string name = loadVariant<std::string>(cfg, "Name");
Ed Tanousbb679322022-05-16 16:10:00 -0700557
558 std::vector<thresholds::Threshold> sensorThresholds;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700559 if (!parseThresholdsFromConfig(interfaces, sensorThresholds))
Ed Tanousbb679322022-05-16 16:10:00 -0700560 {
561 std::cerr << "error populating thresholds for " << name
562 << "\n";
563 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700564 uint8_t deviceAddress = loadVariant<uint8_t>(cfg, "Address");
Ed Tanousbb679322022-05-16 16:10:00 -0700565
Patrick Williams779c96a2023-05-10 07:50:42 -0500566 std::string sensorClass = loadVariant<std::string>(cfg,
567 "Class");
Ed Tanousbb679322022-05-16 16:10:00 -0700568
569 uint8_t hostSMbusIndex = hostSMbusIndexDefault;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700570 auto findSmType = cfg.find("HostSMbusIndex");
571 if (findSmType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700572 {
573 hostSMbusIndex = std::visit(VariantToUnsignedIntVisitor(),
574 findSmType->second);
575 }
576
Zev Weiss8569bf22022-10-11 15:37:44 -0700577 float pollRate = getPollRate(cfg, pollRateDefault);
Ed Tanousbb679322022-05-16 16:10:00 -0700578
Jayashree Dhanapal6ee62942021-12-14 15:22:23 +0530579 uint8_t ipmbBusIndex = ipmbBusIndexDefault;
580 auto findBusType = cfg.find("Bus");
581 if (findBusType != cfg.end())
582 {
583 ipmbBusIndex = std::visit(VariantToUnsignedIntVisitor(),
584 findBusType->second);
585 std::cerr << "Ipmb Bus Index for " << name << " is "
586 << static_cast<int>(ipmbBusIndex) << "\n";
587 }
588
Ed Tanousbb679322022-05-16 16:10:00 -0700589 /* Default sensor type is "temperature" */
590 std::string sensorTypeName = "temperature";
Zev Weiss8ba551b2022-08-12 18:21:02 -0700591 auto findType = cfg.find("SensorType");
592 if (findType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700593 {
Patrick Williams779c96a2023-05-10 07:50:42 -0500594 sensorTypeName = std::visit(VariantToStringVisitor(),
595 findType->second);
Ed Tanousbb679322022-05-16 16:10:00 -0700596 }
597
598 auto& sensor = sensors[name];
Vikash Chandola1f847972022-09-28 09:47:32 +0000599 sensor = nullptr;
600 sensor = std::make_shared<IpmbSensor>(
Zev Weiss8ba551b2022-08-12 18:21:02 -0700601 dbusConnection, io, name, path, objectServer,
Ed Tanousbb679322022-05-16 16:10:00 -0700602 std::move(sensorThresholds), deviceAddress, hostSMbusIndex,
603 pollRate, sensorTypeName);
604
Zev Weiss8ba551b2022-08-12 18:21:02 -0700605 sensor->parseConfigValues(cfg);
Ed Tanousbb679322022-05-16 16:10:00 -0700606 if (!(sensor->sensorClassType(sensorClass)))
607 {
608 continue;
609 }
610 sensor->sensorSubType(sensorTypeName);
611 sensor->init();
James Feist6ef20402019-01-07 16:45:08 -0800612 }
Ed Tanousbb679322022-05-16 16:10:00 -0700613 }
Patrick Williams597e8422023-10-20 11:19:01 -0500614 },
JeffLin2c5a1f22022-10-05 15:19:09 +0800615 entityManagerName, "/xyz/openbmc_project/inventory",
616 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6ef20402019-01-07 16:45:08 -0800617}
618
Jayashree Dhanapal3746c552022-03-21 14:45:52 +0530619void sdrHandler(sdbusplus::message_t& message,
620 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
621{
622 std::string objectName;
623 SensorBaseConfigMap values;
624 message.read(objectName, values);
625
626 auto findBus = values.find("Bus");
627 if (findBus == values.end())
628 {
629 return;
630 }
631
632 uint8_t busIndex = loadVariant<uint8_t>(values, "Bus");
633
634 auto& sdrsen = sdrsensor[busIndex];
635 sdrsen = nullptr;
636 sdrsen = std::make_shared<IpmbSDRDevice>(dbusConnection, busIndex);
637 sdrsen->getSDRRepositoryInfo();
638}
639
Patrick Williams92f8f512022-07-22 19:26:55 -0500640void reinitSensors(sdbusplus::message_t& message)
James Feistf7e2c5d2019-02-13 17:27:51 -0800641{
James Feist0d4f2bd2019-03-05 13:15:40 -0800642 constexpr const size_t reinitWaitSeconds = 2;
James Feistf7e2c5d2019-02-13 17:27:51 -0800643 std::string objectName;
James Feist52497fd2019-06-07 13:01:33 -0700644 boost::container::flat_map<std::string, std::variant<std::string>> values;
James Feistf7e2c5d2019-02-13 17:27:51 -0800645 message.read(objectName, values);
James Feist0d4f2bd2019-03-05 13:15:40 -0800646
James Feist52497fd2019-06-07 13:01:33 -0700647 auto findStatus = values.find(power::property);
648 if (findStatus != values.end())
James Feistf7e2c5d2019-02-13 17:27:51 -0800649 {
Zev Weiss6c106d62022-08-17 20:50:00 -0700650 bool powerStatus =
651 std::get<std::string>(findStatus->second).ends_with(".Running");
James Feistf7e2c5d2019-02-13 17:27:51 -0800652 if (powerStatus)
653 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800654 if (!initCmdTimer)
James Feistf7e2c5d2019-02-13 17:27:51 -0800655 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800656 // this should be impossible
657 return;
James Feistf7e2c5d2019-02-13 17:27:51 -0800658 }
James Feist0d4f2bd2019-03-05 13:15:40 -0800659 // we seem to send this command too fast sometimes, wait before
660 // sending
Ed Tanous83db50c2023-03-01 10:20:24 -0800661 initCmdTimer->expires_after(
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700662 std::chrono::seconds(reinitWaitSeconds));
James Feist0d4f2bd2019-03-05 13:15:40 -0800663
664 initCmdTimer->async_wait([](const boost::system::error_code ec) {
665 if (ec == boost::asio::error::operation_aborted)
666 {
667 return; // we're being canceled
668 }
669
Zev Weiss8ba551b2022-08-12 18:21:02 -0700670 for (const auto& [name, sensor] : sensors)
James Feist0d4f2bd2019-03-05 13:15:40 -0800671 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700672 if (sensor)
James Feist0d4f2bd2019-03-05 13:15:40 -0800673 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700674 sensor->runInitCmd();
James Feist0d4f2bd2019-03-05 13:15:40 -0800675 }
676 }
677 });
James Feistf7e2c5d2019-02-13 17:27:51 -0800678 }
679 }
680}
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}
715
James Feistb6c0b912019-07-09 12:21:44 -0700716int main()
James Feist6ef20402019-01-07 16:45:08 -0800717{
Ed Tanous1f978632023-02-28 18:16:39 -0800718 boost::asio::io_context io;
James Feist6ef20402019-01-07 16:45:08 -0800719 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanous14ed5e92022-07-12 15:50:23 -0700720 sdbusplus::asio::object_server objectServer(systemBus, true);
721 objectServer.add_manager("/xyz/openbmc_project/sensors");
James Feist6ef20402019-01-07 16:45:08 -0800722 systemBus->request_name("xyz.openbmc_project.IpmbSensor");
James Feist6ef20402019-01-07 16:45:08 -0800723
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700724 initCmdTimer = std::make_unique<boost::asio::steady_timer>(io);
James Feist0d4f2bd2019-03-05 13:15:40 -0800725
Ed Tanous83db50c2023-03-01 10:20:24 -0800726 boost::asio::post(
727 io, [&]() { createSensors(io, objectServer, sensors, systemBus); });
James Feist6ef20402019-01-07 16:45:08 -0800728
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700729 boost::asio::steady_timer configTimer(io);
James Feist6ef20402019-01-07 16:45:08 -0800730
Patrick Williams92f8f512022-07-22 19:26:55 -0500731 std::function<void(sdbusplus::message_t&)> eventHandler =
732 [&](sdbusplus::message_t&) {
Ed Tanous83db50c2023-03-01 10:20:24 -0800733 configTimer.expires_after(std::chrono::seconds(1));
Ed Tanousbb679322022-05-16 16:10:00 -0700734 // create a timer because normally multiple properties change
735 configTimer.async_wait([&](const boost::system::error_code& ec) {
736 if (ec == boost::asio::error::operation_aborted)
737 {
738 return; // we're being canceled
739 }
740 createSensors(io, objectServer, sensors, systemBus);
741 if (sensors.empty())
742 {
743 std::cout << "Configuration not detected\n";
744 }
745 });
746 };
James Feist6ef20402019-01-07 16:45:08 -0800747
Zev Weiss214d9712022-08-12 12:54:31 -0700748 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
749 setupPropertiesChangedMatches(
Zev Weiss054aad82022-08-18 01:37:34 -0700750 *systemBus, std::to_array<const char*>({sensorType}), eventHandler);
James Feist6ef20402019-01-07 16:45:08 -0800751
Patrick Williams92f8f512022-07-22 19:26:55 -0500752 sdbusplus::bus::match_t powerChangeMatch(
753 static_cast<sdbusplus::bus_t&>(*systemBus),
James Feist52497fd2019-06-07 13:01:33 -0700754 "type='signal',interface='" + std::string(properties::interface) +
755 "',path='" + std::string(power::path) + "',arg0='" +
756 std::string(power::interface) + "'",
James Feistf7e2c5d2019-02-13 17:27:51 -0800757 reinitSensors);
758
Jayashree Dhanapal3746c552022-03-21 14:45:52 +0530759 auto matchSignal = std::make_shared<sdbusplus::bus::match_t>(
760 static_cast<sdbusplus::bus_t&>(*systemBus),
761 "type='signal',member='PropertiesChanged',path_namespace='" +
762 std::string(inventoryPath) + "',arg0namespace='" +
763 configInterfaceName(sdrInterface) + "'",
764 [&systemBus](sdbusplus::message_t& msg) {
765 sdrHandler(msg, systemBus);
Patrick Williams597e8422023-10-20 11:19:01 -0500766 });
Jayashree Dhanapal3746c552022-03-21 14:45:52 +0530767
Kumar Thangavel5d032bc2022-11-30 20:24:47 +0530768 // Watch for entity-manager to remove configuration interfaces
769 // so the corresponding sensors can be removed.
770 auto ifaceRemovedMatch = std::make_shared<sdbusplus::bus::match_t>(
771 static_cast<sdbusplus::bus_t&>(*systemBus),
772 "type='signal',member='InterfacesRemoved',arg0path='" +
773 std::string(inventoryPath) + "/'",
Willy Tu63c91222023-07-21 10:17:16 -0700774 [](sdbusplus::message_t& msg) { interfaceRemoved(msg, sensors); });
Kumar Thangavel5d032bc2022-11-30 20:24:47 +0530775
Bruce Lee1263c3d2021-06-04 15:16:33 +0800776 setupManufacturingModeMatch(*systemBus);
James Feist6ef20402019-01-07 16:45:08 -0800777 io.run();
Zhikui Rene76a5a62021-07-09 15:16:32 -0700778 return 0;
James Feist6ef20402019-01-07 16:45:08 -0800779}