blob: ba39214de74da3ef9d6e818e7d56c9eed829194c [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
Jayashree Dhanapal3746c552022-03-21 14:45:52 +053017#include <IpmbSDRSensor.hpp>
Ed Tanous8a57ec02020-10-09 12:46:52 -070018#include <IpmbSensor.hpp>
19#include <Utils.hpp>
20#include <VariantVisitors.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070021#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070022#include <sdbusplus/asio/connection.hpp>
23#include <sdbusplus/asio/object_server.hpp>
24#include <sdbusplus/bus/match.hpp>
25
James Feist6ef20402019-01-07 16:45:08 -080026#include <chrono>
Ed Tanous8a57ec02020-10-09 12:46:52 -070027#include <cmath>
Patrick Venture96e97db2019-10-31 13:44:38 -070028#include <functional>
James Feist6ef20402019-01-07 16:45:08 -080029#include <iostream>
30#include <limits>
Patrick Venture96e97db2019-10-31 13:44:38 -070031#include <memory>
James Feist6ef20402019-01-07 16:45:08 -080032#include <numeric>
Patrick Venture96e97db2019-10-31 13:44:38 -070033#include <string>
34#include <tuple>
35#include <variant>
James Feist6ef20402019-01-07 16:45:08 -080036#include <vector>
37
38constexpr const bool debug = false;
39
Zev Weiss054aad82022-08-18 01:37:34 -070040constexpr const char* sensorType = "IpmbSensor";
Jayashree Dhanapal3746c552022-03-21 14:45:52 +053041constexpr const char* sdrInterface = "IpmbDevice";
42
James Feist6ef20402019-01-07 16:45:08 -080043static constexpr double ipmbMaxReading = 0xFF;
44static constexpr double ipmbMinReading = 0;
45
46static constexpr uint8_t meAddress = 1;
47static constexpr uint8_t lun = 0;
Anoop S832a2c62020-11-20 19:21:22 +000048static constexpr uint8_t hostSMbusIndexDefault = 0x03;
Jayashree Dhanapal6ee62942021-12-14 15:22:23 +053049static constexpr uint8_t ipmbBusIndexDefault = 0;
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053050static constexpr float pollRateDefault = 1; // in seconds
James Feist6ef20402019-01-07 16:45:08 -080051
Vijay Khemka682a5cb2019-07-18 17:34:03 -070052static constexpr const char* sensorPathPrefix = "/xyz/openbmc_project/sensors/";
53
Vikash Chandola1f847972022-09-28 09:47:32 +000054boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>> sensors;
Jayashree Dhanapal3746c552022-03-21 14:45:52 +053055boost::container::flat_map<uint8_t, std::shared_ptr<IpmbSDRDevice>> sdrsensor;
James Feistf7e2c5d2019-02-13 17:27:51 -080056
Ed Tanous9b4a20e2022-09-06 08:47:11 -070057std::unique_ptr<boost::asio::steady_timer> initCmdTimer;
James Feist0d4f2bd2019-03-05 13:15:40 -080058
James Feist6ef20402019-01-07 16:45:08 -080059IpmbSensor::IpmbSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
60 boost::asio::io_service& io,
61 const std::string& sensorName,
62 const std::string& sensorConfiguration,
63 sdbusplus::asio::object_server& objectServer,
64 std::vector<thresholds::Threshold>&& thresholdData,
Anoop S832a2c62020-11-20 19:21:22 +000065 uint8_t deviceAddress, uint8_t hostSMbusIndex,
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053066 const float pollRate, std::string& sensorTypeName) :
Zhikui Renda98f092021-11-01 09:41:08 -070067 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -070068 sensorConfiguration, "IpmbSensor", false, false, ipmbMaxReading,
69 ipmbMinReading, conn, PowerState::on),
Anoop S832a2c62020-11-20 19:21:22 +000070 deviceAddress(deviceAddress), hostSMbusIndex(hostSMbusIndex),
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053071 sensorPollMs(static_cast<int>(pollRate * 1000)), objectServer(objectServer),
72 waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080073{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070074 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
75
James Feist6ef20402019-01-07 16:45:08 -080076 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070077 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080078
Jayashree Dhanapal56678082022-01-04 17:27:20 +053079 for (const auto& threshold : thresholds)
James Feist6ef20402019-01-07 16:45:08 -080080 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053081 std::string interface = thresholds::getInterface(threshold.level);
82 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
83 objectServer.add_interface(dbusPath, interface);
James Feist6ef20402019-01-07 16:45:08 -080084 }
James Feist2adc95c2019-09-30 14:55:28 -070085 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -080086}
87
88IpmbSensor::~IpmbSensor()
89{
90 waitTimer.cancel();
Jayashree Dhanapal56678082022-01-04 17:27:20 +053091 for (const auto& iface : thresholdInterfaces)
92 {
93 objectServer.remove_interface(iface);
94 }
James Feist6ef20402019-01-07 16:45:08 -080095 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -080096 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -080097}
98
Ed Tanous2049bd22022-07-09 07:20:26 -070099std::string IpmbSensor::getSubTypeUnits(void) const
Zev Weiss6b6891c2021-04-22 02:46:21 -0500100{
101 switch (subType)
102 {
103 case IpmbSubType::temp:
104 return sensor_paths::unitDegreesC;
105 case IpmbSubType::curr:
106 return sensor_paths::unitAmperes;
107 case IpmbSubType::power:
108 return sensor_paths::unitWatts;
109 case IpmbSubType::volt:
110 return sensor_paths::unitVolts;
111 case IpmbSubType::util:
112 return sensor_paths::unitPercent;
113 default:
114 throw std::runtime_error("Invalid sensor type");
115 }
116}
117
James Feist6ef20402019-01-07 16:45:08 -0800118void IpmbSensor::init(void)
119{
James Feist6ef20402019-01-07 16:45:08 -0800120 loadDefaults();
Andrei Kartashev39287412022-02-04 16:04:47 +0300121 setInitialProperties(getSubTypeUnits());
James Feist6ef20402019-01-07 16:45:08 -0800122 if (initCommand)
123 {
James Feistf7e2c5d2019-02-13 17:27:51 -0800124 runInitCmd();
125 }
126 read();
127}
128
Vikash Chandola1f847972022-09-28 09:47:32 +0000129static void initCmdCb(const std::weak_ptr<IpmbSensor>& weakRef,
130 const boost::system::error_code& ec,
131 const IpmbMethodType& response)
132{
133 std::shared_ptr<IpmbSensor> self = weakRef.lock();
134 if (!self)
135 {
136 return;
137 }
138 const int& status = std::get<0>(response);
139 if (ec || (status != 0))
140 {
141 std::cerr << "Error setting init command for device: " << self->name
142 << "\n";
143 }
144}
145
James Feistf7e2c5d2019-02-13 17:27:51 -0800146void IpmbSensor::runInitCmd()
147{
Vikash Chandola1f847972022-09-28 09:47:32 +0000148 if (!initCommand)
James Feistf7e2c5d2019-02-13 17:27:51 -0800149 {
Vikash Chandola1f847972022-09-28 09:47:32 +0000150 return;
James Feist6ef20402019-01-07 16:45:08 -0800151 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000152 dbusConnection->async_method_call(
153 [weakRef{weak_from_this()}](const boost::system::error_code& ec,
154 const IpmbMethodType& response) {
155 initCmdCb(weakRef, ec, response);
156 },
157 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
158 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
159 "sendRequest", commandAddress, netfn, lun, *initCommand, initData);
James Feist6ef20402019-01-07 16:45:08 -0800160}
161
162void IpmbSensor::loadDefaults()
163{
164 if (type == IpmbType::meSensor)
165 {
166 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200167 netfn = ipmi::sensor::netFn;
168 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800169 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700170 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800171 }
172 else if (type == IpmbType::PXE1410CVR)
173 {
174 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200175 netfn = ipmi::me_bridge::netFn;
176 command = ipmi::me_bridge::sendRawPmbus;
177 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700178 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000179 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
180 deviceAddress, 0x00, 0x00, 0x00, 0x00,
181 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700182 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000183 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
184 deviceAddress, 0x00, 0x00, 0x00, 0x00,
185 0x02, 0x00, 0x00, 0x00};
Jayashree-D37322572021-03-19 17:40:56 +0530186 readingFormat = ReadingFormat::linearElevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800187 }
188 else if (type == IpmbType::IR38363VR)
189 {
190 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200191 netfn = ipmi::me_bridge::netFn;
192 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700193 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000194 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
195 deviceAddress, 00, 0x00, 0x00, 0x00,
196 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700197 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800198 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700199 else if (type == IpmbType::ADM1278HSC)
200 {
201 commandAddress = meAddress;
Ed Tanousa771f6a2022-01-14 09:36:51 -0800202 uint8_t snsNum = 0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700203 switch (subType)
204 {
205 case IpmbSubType::temp:
206 case IpmbSubType::curr:
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700207 if (subType == IpmbSubType::temp)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700208 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700209 snsNum = 0x8d;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700210 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700211 else
Ed Tanous8a57ec02020-10-09 12:46:52 -0700212 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700213 snsNum = 0x8c;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700214 }
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200215 netfn = ipmi::me_bridge::netFn;
216 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700217 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
218 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700219 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700220 break;
221 case IpmbSubType::power:
222 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200223 netfn = ipmi::sensor::netFn;
224 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700225 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700226 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700227 break;
228 default:
229 throw std::runtime_error("Invalid sensor type");
230 }
231 }
James Feist6ef20402019-01-07 16:45:08 -0800232 else if (type == IpmbType::mpsVR)
233 {
234 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200235 netfn = ipmi::me_bridge::netFn;
236 command = ipmi::me_bridge::sendRawPmbus;
237 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700238 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000239 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
240 deviceAddress, 0x00, 0x00, 0x00, 0x00,
241 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700242 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000243 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
244 deviceAddress, 0x00, 0x00, 0x00, 0x00,
245 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700246 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800247 }
248 else
249 {
250 throw std::runtime_error("Invalid sensor type");
251 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200252
253 if (subType == IpmbSubType::util)
254 {
255 // Utilization need to be scaled to percent
256 maxValue = 100;
257 minValue = 0;
258 }
James Feist6ef20402019-01-07 16:45:08 -0800259}
260
261void IpmbSensor::checkThresholds(void)
262{
James Feist6ef20402019-01-07 16:45:08 -0800263 thresholds::checkThresholds(this);
264}
265
James Feist961bf092020-07-01 16:38:12 -0700266bool IpmbSensor::processReading(const std::vector<uint8_t>& data, double& resp)
James Feistd7ae29a2020-06-25 15:42:46 -0700267{
268
269 switch (readingFormat)
270 {
271 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700272 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200273 if (command == ipmi::sensor::getSensorReading &&
274 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700275 {
276 return false;
277 }
James Feist961bf092020-07-01 16:38:12 -0700278 resp = data[0];
279 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700280 }
James Feistd7ae29a2020-06-25 15:42:46 -0700281 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700282 {
James Feistd7ae29a2020-06-25 15:42:46 -0700283 if (data.size() < 4)
284 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700285 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700286 {
287 std::cerr << "Invalid data length returned for " << name
288 << "\n";
289 }
290 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700291 }
James Feist961bf092020-07-01 16:38:12 -0700292 resp = data[3];
293 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700294 }
James Feistd7ae29a2020-06-25 15:42:46 -0700295 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700296 {
James Feistd7ae29a2020-06-25 15:42:46 -0700297 if (data.size() < 5)
298 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700299 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700300 {
301 std::cerr << "Invalid data length returned for " << name
302 << "\n";
303 }
304 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700305 }
306
James Feiste4a970d2020-08-19 11:21:58 -0700307 int16_t value = ((data[4] << 8) | data[3]);
James Feiste4a970d2020-08-19 11:21:58 -0700308 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700309 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700310 }
James Feistd7ae29a2020-06-25 15:42:46 -0700311 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700312 {
James Feistd7ae29a2020-06-25 15:42:46 -0700313 if (data.size() < 5)
314 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700315 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700316 {
317 std::cerr << "Invalid data length returned for " << name
318 << "\n";
319 }
320 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700321 }
322
James Feist961bf092020-07-01 16:38:12 -0700323 resp = ((data[4] << 8) | data[3]) >> 3;
324 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700325 }
Jayashree-D37322572021-03-19 17:40:56 +0530326 case (ReadingFormat::linearElevenBit):
327 {
328 if (data.size() < 5)
329 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700330 if (errCount == 0U)
Jayashree-D37322572021-03-19 17:40:56 +0530331 {
332 std::cerr << "Invalid data length returned for " << name
333 << "\n";
334 }
335 return false;
336 }
337
338 int16_t value = ((data[4] << 8) | data[3]);
339 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
340 value <<= shift;
341 value >>= shift;
342 resp = value;
343 return true;
344 }
James Feistd7ae29a2020-06-25 15:42:46 -0700345 default:
346 throw std::runtime_error("Invalid reading type");
347 }
348}
349
Vikash Chandola1f847972022-09-28 09:47:32 +0000350void IpmbSensor::ipmbRequestCompletionCb(const boost::system::error_code& ec,
351 const IpmbMethodType& response)
352{
353 const int& status = std::get<0>(response);
354 if (ec || (status != 0))
355 {
356 incrementError();
357 read();
358 return;
359 }
360 const std::vector<uint8_t>& data = std::get<5>(response);
361 if constexpr (debug)
362 {
363 std::cout << name << ": ";
364 for (size_t d : data)
365 {
366 std::cout << d << " ";
367 }
368 std::cout << "\n";
369 }
370 if (data.empty())
371 {
372 incrementError();
373 read();
374 return;
375 }
376
377 double value = 0;
378
379 if (!processReading(data, value))
380 {
381 incrementError();
382 read();
383 return;
384 }
385
386 // rawValue only used in debug logging
387 // up to 5th byte in data are used to derive value
388 size_t end = std::min(sizeof(uint64_t), data.size());
389 uint64_t rawData = 0;
390 for (size_t i = 0; i < end; i++)
391 {
392 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
393 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
394 }
395 rawValue = static_cast<double>(rawData);
396
397 /* Adjust value as per scale and offset */
398 value = (value * scaleVal) + offsetVal;
399 updateValue(value);
400 read();
401}
402
James Feist6ef20402019-01-07 16:45:08 -0800403void IpmbSensor::read(void)
404{
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700405 waitTimer.expires_from_now(std::chrono::milliseconds(sensorPollMs));
Vikash Chandola1f847972022-09-28 09:47:32 +0000406 waitTimer.async_wait(
407 [weakRef{weak_from_this()}](const boost::system::error_code& ec) {
James Feist6ef20402019-01-07 16:45:08 -0800408 if (ec == boost::asio::error::operation_aborted)
409 {
410 return; // we're being canceled
411 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000412 std::shared_ptr<IpmbSensor> self = weakRef.lock();
413 if (!self)
James Feist6ef20402019-01-07 16:45:08 -0800414 {
James Feist6ef20402019-01-07 16:45:08 -0800415 return;
416 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000417 self->sendIpmbRequest();
James Feist6ef20402019-01-07 16:45:08 -0800418 });
419}
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530420
Vikash Chandola1f847972022-09-28 09:47:32 +0000421void IpmbSensor::sendIpmbRequest()
422{
423 if (!readingStateGood())
424 {
425 updateValue(std::numeric_limits<double>::quiet_NaN());
426 read();
427 return;
428 }
429 dbusConnection->async_method_call(
430 [weakRef{weak_from_this()}](boost::system::error_code ec,
431 const IpmbMethodType& response) {
432 std::shared_ptr<IpmbSensor> self = weakRef.lock();
433 if (!self)
434 {
435 return;
436 }
437 self->ipmbRequestCompletionCb(ec, response);
438 },
439 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
440 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
441 "sendRequest", commandAddress, netfn, lun, command, commandData);
442}
443
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530444bool IpmbSensor::sensorClassType(const std::string& sensorClass)
445{
446 if (sensorClass == "PxeBridgeTemp")
447 {
448 type = IpmbType::PXE1410CVR;
449 }
450 else if (sensorClass == "IRBridgeTemp")
451 {
452 type = IpmbType::IR38363VR;
453 }
454 else if (sensorClass == "HSCBridge")
455 {
456 type = IpmbType::ADM1278HSC;
457 }
458 else if (sensorClass == "MpsBridgeTemp")
459 {
460 type = IpmbType::mpsVR;
461 }
462 else if (sensorClass == "METemp" || sensorClass == "MESensor")
463 {
464 type = IpmbType::meSensor;
465 }
466 else
467 {
468 std::cerr << "Invalid class " << sensorClass << "\n";
469 return false;
470 }
471 return true;
472}
473
474void IpmbSensor::sensorSubType(const std::string& sensorTypeName)
475{
476 if (sensorTypeName == "voltage")
477 {
478 subType = IpmbSubType::volt;
479 }
480 else if (sensorTypeName == "power")
481 {
482 subType = IpmbSubType::power;
483 }
484 else if (sensorTypeName == "current")
485 {
486 subType = IpmbSubType::curr;
487 }
488 else if (sensorTypeName == "utilization")
489 {
490 subType = IpmbSubType::util;
491 }
492 else
493 {
494 subType = IpmbSubType::temp;
495 }
496}
497
498void IpmbSensor::parseConfigValues(const SensorBaseConfigMap& entry)
499{
500 auto findScaleVal = entry.find("ScaleValue");
501 if (findScaleVal != entry.end())
502 {
503 scaleVal = std::visit(VariantToDoubleVisitor(), findScaleVal->second);
504 }
505
506 auto findOffsetVal = entry.find("OffsetValue");
507 if (findOffsetVal != entry.end())
508 {
509 offsetVal = std::visit(VariantToDoubleVisitor(), findOffsetVal->second);
510 }
511
Zev Weissa4d27682022-07-19 15:30:36 -0700512 readState = getPowerState(entry);
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530513}
514
James Feist6ef20402019-01-07 16:45:08 -0800515void createSensors(
516 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
Vikash Chandola1f847972022-09-28 09:47:32 +0000517 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
James Feist6ef20402019-01-07 16:45:08 -0800518 sensors,
519 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
520{
521 if (!dbusConnection)
522 {
523 std::cerr << "Connection not created\n";
524 return;
525 }
526 dbusConnection->async_method_call(
527 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
Ed Tanousbb679322022-05-16 16:10:00 -0700528 if (ec)
529 {
530 std::cerr << "Error contacting entity manager\n";
531 return;
532 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700533 for (const auto& [path, interfaces] : resp)
Ed Tanousbb679322022-05-16 16:10:00 -0700534 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700535 for (const auto& [intf, cfg] : interfaces)
James Feist6ef20402019-01-07 16:45:08 -0800536 {
Zev Weiss054aad82022-08-18 01:37:34 -0700537 if (intf != configInterfaceName(sensorType))
James Feist6ef20402019-01-07 16:45:08 -0800538 {
Ed Tanousbb679322022-05-16 16:10:00 -0700539 continue;
James Feist6ef20402019-01-07 16:45:08 -0800540 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700541 std::string name = loadVariant<std::string>(cfg, "Name");
Ed Tanousbb679322022-05-16 16:10:00 -0700542
543 std::vector<thresholds::Threshold> sensorThresholds;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700544 if (!parseThresholdsFromConfig(interfaces, sensorThresholds))
Ed Tanousbb679322022-05-16 16:10:00 -0700545 {
546 std::cerr << "error populating thresholds for " << name
547 << "\n";
548 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700549 uint8_t deviceAddress = loadVariant<uint8_t>(cfg, "Address");
Ed Tanousbb679322022-05-16 16:10:00 -0700550
551 std::string sensorClass =
Zev Weiss8ba551b2022-08-12 18:21:02 -0700552 loadVariant<std::string>(cfg, "Class");
Ed Tanousbb679322022-05-16 16:10:00 -0700553
554 uint8_t hostSMbusIndex = hostSMbusIndexDefault;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700555 auto findSmType = cfg.find("HostSMbusIndex");
556 if (findSmType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700557 {
558 hostSMbusIndex = std::visit(VariantToUnsignedIntVisitor(),
559 findSmType->second);
560 }
561
Zev Weiss8569bf22022-10-11 15:37:44 -0700562 float pollRate = getPollRate(cfg, pollRateDefault);
Ed Tanousbb679322022-05-16 16:10:00 -0700563
Jayashree Dhanapal6ee62942021-12-14 15:22:23 +0530564 uint8_t ipmbBusIndex = ipmbBusIndexDefault;
565 auto findBusType = cfg.find("Bus");
566 if (findBusType != cfg.end())
567 {
568 ipmbBusIndex = std::visit(VariantToUnsignedIntVisitor(),
569 findBusType->second);
570 std::cerr << "Ipmb Bus Index for " << name << " is "
571 << static_cast<int>(ipmbBusIndex) << "\n";
572 }
573
Ed Tanousbb679322022-05-16 16:10:00 -0700574 /* Default sensor type is "temperature" */
575 std::string sensorTypeName = "temperature";
Zev Weiss8ba551b2022-08-12 18:21:02 -0700576 auto findType = cfg.find("SensorType");
577 if (findType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700578 {
579 sensorTypeName =
580 std::visit(VariantToStringVisitor(), findType->second);
581 }
582
583 auto& sensor = sensors[name];
Vikash Chandola1f847972022-09-28 09:47:32 +0000584 sensor = nullptr;
585 sensor = std::make_shared<IpmbSensor>(
Zev Weiss8ba551b2022-08-12 18:21:02 -0700586 dbusConnection, io, name, path, objectServer,
Ed Tanousbb679322022-05-16 16:10:00 -0700587 std::move(sensorThresholds), deviceAddress, hostSMbusIndex,
588 pollRate, sensorTypeName);
589
Zev Weiss8ba551b2022-08-12 18:21:02 -0700590 sensor->parseConfigValues(cfg);
Ed Tanousbb679322022-05-16 16:10:00 -0700591 if (!(sensor->sensorClassType(sensorClass)))
592 {
593 continue;
594 }
595 sensor->sensorSubType(sensorTypeName);
596 sensor->init();
James Feist6ef20402019-01-07 16:45:08 -0800597 }
Ed Tanousbb679322022-05-16 16:10:00 -0700598 }
James Feist6ef20402019-01-07 16:45:08 -0800599 },
JeffLin2c5a1f22022-10-05 15:19:09 +0800600 entityManagerName, "/xyz/openbmc_project/inventory",
601 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6ef20402019-01-07 16:45:08 -0800602}
603
Jayashree Dhanapal3746c552022-03-21 14:45:52 +0530604void sdrHandler(sdbusplus::message_t& message,
605 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
606{
607 std::string objectName;
608 SensorBaseConfigMap values;
609 message.read(objectName, values);
610
611 auto findBus = values.find("Bus");
612 if (findBus == values.end())
613 {
614 return;
615 }
616
617 uint8_t busIndex = loadVariant<uint8_t>(values, "Bus");
618
619 auto& sdrsen = sdrsensor[busIndex];
620 sdrsen = nullptr;
621 sdrsen = std::make_shared<IpmbSDRDevice>(dbusConnection, busIndex);
622 sdrsen->getSDRRepositoryInfo();
623}
624
Patrick Williams92f8f512022-07-22 19:26:55 -0500625void reinitSensors(sdbusplus::message_t& message)
James Feistf7e2c5d2019-02-13 17:27:51 -0800626{
James Feist0d4f2bd2019-03-05 13:15:40 -0800627 constexpr const size_t reinitWaitSeconds = 2;
James Feistf7e2c5d2019-02-13 17:27:51 -0800628 std::string objectName;
James Feist52497fd2019-06-07 13:01:33 -0700629 boost::container::flat_map<std::string, std::variant<std::string>> values;
James Feistf7e2c5d2019-02-13 17:27:51 -0800630 message.read(objectName, values);
James Feist0d4f2bd2019-03-05 13:15:40 -0800631
James Feist52497fd2019-06-07 13:01:33 -0700632 auto findStatus = values.find(power::property);
633 if (findStatus != values.end())
James Feistf7e2c5d2019-02-13 17:27:51 -0800634 {
Zev Weiss6c106d62022-08-17 20:50:00 -0700635 bool powerStatus =
636 std::get<std::string>(findStatus->second).ends_with(".Running");
James Feistf7e2c5d2019-02-13 17:27:51 -0800637 if (powerStatus)
638 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800639 if (!initCmdTimer)
James Feistf7e2c5d2019-02-13 17:27:51 -0800640 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800641 // this should be impossible
642 return;
James Feistf7e2c5d2019-02-13 17:27:51 -0800643 }
James Feist0d4f2bd2019-03-05 13:15:40 -0800644 // we seem to send this command too fast sometimes, wait before
645 // sending
646 initCmdTimer->expires_from_now(
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700647 std::chrono::seconds(reinitWaitSeconds));
James Feist0d4f2bd2019-03-05 13:15:40 -0800648
649 initCmdTimer->async_wait([](const boost::system::error_code ec) {
650 if (ec == boost::asio::error::operation_aborted)
651 {
652 return; // we're being canceled
653 }
654
Zev Weiss8ba551b2022-08-12 18:21:02 -0700655 for (const auto& [name, sensor] : sensors)
James Feist0d4f2bd2019-03-05 13:15:40 -0800656 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700657 if (sensor)
James Feist0d4f2bd2019-03-05 13:15:40 -0800658 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700659 sensor->runInitCmd();
James Feist0d4f2bd2019-03-05 13:15:40 -0800660 }
661 }
662 });
James Feistf7e2c5d2019-02-13 17:27:51 -0800663 }
664 }
665}
666
James Feistb6c0b912019-07-09 12:21:44 -0700667int main()
James Feist6ef20402019-01-07 16:45:08 -0800668{
669
670 boost::asio::io_service io;
671 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanous14ed5e92022-07-12 15:50:23 -0700672 sdbusplus::asio::object_server objectServer(systemBus, true);
673 objectServer.add_manager("/xyz/openbmc_project/sensors");
James Feist6ef20402019-01-07 16:45:08 -0800674 systemBus->request_name("xyz.openbmc_project.IpmbSensor");
James Feist6ef20402019-01-07 16:45:08 -0800675
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700676 initCmdTimer = std::make_unique<boost::asio::steady_timer>(io);
James Feist0d4f2bd2019-03-05 13:15:40 -0800677
James Feist6ef20402019-01-07 16:45:08 -0800678 io.post([&]() { createSensors(io, objectServer, sensors, systemBus); });
679
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700680 boost::asio::steady_timer configTimer(io);
James Feist6ef20402019-01-07 16:45:08 -0800681
Patrick Williams92f8f512022-07-22 19:26:55 -0500682 std::function<void(sdbusplus::message_t&)> eventHandler =
683 [&](sdbusplus::message_t&) {
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700684 configTimer.expires_from_now(std::chrono::seconds(1));
Ed Tanousbb679322022-05-16 16:10:00 -0700685 // create a timer because normally multiple properties change
686 configTimer.async_wait([&](const boost::system::error_code& ec) {
687 if (ec == boost::asio::error::operation_aborted)
688 {
689 return; // we're being canceled
690 }
691 createSensors(io, objectServer, sensors, systemBus);
692 if (sensors.empty())
693 {
694 std::cout << "Configuration not detected\n";
695 }
696 });
697 };
James Feist6ef20402019-01-07 16:45:08 -0800698
Zev Weiss214d9712022-08-12 12:54:31 -0700699 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
700 setupPropertiesChangedMatches(
Zev Weiss054aad82022-08-18 01:37:34 -0700701 *systemBus, std::to_array<const char*>({sensorType}), eventHandler);
James Feist6ef20402019-01-07 16:45:08 -0800702
Patrick Williams92f8f512022-07-22 19:26:55 -0500703 sdbusplus::bus::match_t powerChangeMatch(
704 static_cast<sdbusplus::bus_t&>(*systemBus),
James Feist52497fd2019-06-07 13:01:33 -0700705 "type='signal',interface='" + std::string(properties::interface) +
706 "',path='" + std::string(power::path) + "',arg0='" +
707 std::string(power::interface) + "'",
James Feistf7e2c5d2019-02-13 17:27:51 -0800708 reinitSensors);
709
Jayashree Dhanapal3746c552022-03-21 14:45:52 +0530710 auto matchSignal = std::make_shared<sdbusplus::bus::match_t>(
711 static_cast<sdbusplus::bus_t&>(*systemBus),
712 "type='signal',member='PropertiesChanged',path_namespace='" +
713 std::string(inventoryPath) + "',arg0namespace='" +
714 configInterfaceName(sdrInterface) + "'",
715 [&systemBus](sdbusplus::message_t& msg) {
716 sdrHandler(msg, systemBus);
717 });
718
Bruce Lee1263c3d2021-06-04 15:16:33 +0800719 setupManufacturingModeMatch(*systemBus);
James Feist6ef20402019-01-07 16:45:08 -0800720 io.run();
Zhikui Rene76a5a62021-07-09 15:16:32 -0700721 return 0;
James Feist6ef20402019-01-07 16:45:08 -0800722}