blob: c341c190e2e1478b32f819cef4f77e7b2c26160a [file]
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION &
* AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "config.h"
#include "nsmNumericSensor.hpp"
#include "sensorManager.hpp"
#include "utils.hpp"
#include <endian.h>
#include <tal.hpp>
namespace nsm
{
#ifdef NVIDIA_SHMEM
const std::string NsmNumericSensorShmem::valueInterface{
"xyz.openbmc_project.Sensor.Value"};
const std::string NsmNumericSensorShmem::valueProperty{"Value"};
#endif
using namespace std::string_literals;
NsmNumericSensorDbusValue::NsmNumericSensorDbusValue(
sdbusplus::bus::bus& bus, const std::string& name,
const std::string& sensor_type, const SensorUnit unit,
const std::vector<utils::Association>& associations,
const std::string& physicalContext, const std::string* implementation,
const double maxAllowableValue, const std::string* readingBasis,
const std::string* description) :
valueIntf(
bus,
("/xyz/openbmc_project/sensors/"s + sensor_type + '/' + name).c_str()),
associationDefinitionsIntf(
bus,
("/xyz/openbmc_project/sensors/"s + sensor_type + '/' + name).c_str()),
decoratorAreaIntf(
bus,
("/xyz/openbmc_project/sensors/"s + sensor_type + '/' + name).c_str())
{
valueIntf.unit(unit);
valueIntf.maxAllowableValue(maxAllowableValue);
decoratorAreaIntf.physicalContext(
sdbusplus::common::xyz::openbmc_project::inventory::decorator::Area::
convertPhysicalContextTypeFromString(
"xyz.openbmc_project.Inventory.Decorator.Area.PhysicalContextType." +
physicalContext));
if (implementation)
{
typeIntf = std::make_unique<TypeIntf>(
bus, ("/xyz/openbmc_project/sensors/"s + sensor_type + '/' + name)
.c_str());
typeIntf->implementation(
sdbusplus::common::xyz::openbmc_project::sensor::Type::
convertImplementationTypeFromString(
"xyz.openbmc_project.Sensor.Type.ImplementationType." +
*implementation));
}
if (readingBasis)
{
readingBasisIntf = std::make_unique<ReadingBasisIntf>(
bus, ("/xyz/openbmc_project/sensors/"s + sensor_type + '/' + name)
.c_str());
readingBasisIntf->readingBasis(
sdbusplus::common::xyz::openbmc_project::sensor::ReadingBasis::
convertReadingBasisTypeFromString(
"xyz.openbmc_project.Sensor.ReadingBasis.ReadingBasisType." +
*readingBasis));
}
if (description)
{
descriptionIntf = std::make_unique<DescriptionIntf>(
bus, ("/xyz/openbmc_project/sensors/"s + sensor_type + '/' + name)
.c_str());
descriptionIntf->description(*description);
}
std::vector<std::tuple<std::string, std::string, std::string>>
associations_list;
for (const auto& association : associations)
{
associations_list.emplace_back(association.forward,
association.backward,
association.absolutePath);
}
associationDefinitionsIntf.associations(associations_list);
updateReading(std::numeric_limits<double>::quiet_NaN());
}
void NsmNumericSensorDbusValue::updateReading(double value,
uint64_t /*timestamp*/)
{
valueIntf.value(value);
}
NsmNumericSensorDbusValueTimestamp::NsmNumericSensorDbusValueTimestamp(
sdbusplus::bus::bus& bus, const std::string& name,
const std::string& sensor_type, const SensorUnit unit,
const std::vector<utils::Association>& association,
const std::string& physicalContext, const std::string* implementation,
const double maxAllowableValue, const std::string* readingBasis,
const std::string* description) :
NsmNumericSensorDbusValue(bus, name, sensor_type, unit, association,
physicalContext, implementation,
maxAllowableValue, readingBasis, description),
timestampIntf(
bus,
("/xyz/openbmc_project/sensors/"s + sensor_type + '/' + name).c_str())
{}
void NsmNumericSensorDbusValueTimestamp::updateReading(double value,
uint64_t timestamp)
{
timestampIntf.elapsed(timestamp);
NsmNumericSensorDbusValue::updateReading(value);
}
NsmNumericSensorDbusPeakValueTimestamp::NsmNumericSensorDbusPeakValueTimestamp(
sdbusplus::bus::bus& bus, const char* objectPath) :
peakValueIntf(bus, objectPath)
{}
void NsmNumericSensorDbusPeakValueTimestamp::updateReading(double value,
uint64_t timestamp)
{
peakValueIntf.peakValue(value);
peakValueIntf.timestamp(timestamp);
}
void NsmNumericSensorValueAggregate::append(
std::unique_ptr<NsmNumericSensorValue> elem)
{
objects.push_back(std::move(elem));
}
void NsmNumericSensorValueAggregate::updateReading(double value,
uint64_t timestamp)
{
for (const auto& elem : objects)
{
elem->updateReading(value, timestamp);
}
}
NsmNumericSensorDbusStatus::NsmNumericSensorDbusStatus(
sdbusplus::bus::bus& bus, const std::string& name,
const std::string& sensor_type) :
availabilityIntf(
bus,
("/xyz/openbmc_project/sensors/"s + sensor_type + '/' + name).c_str()),
operationalStatusIntf(
bus,
("/xyz/openbmc_project/sensors/"s + sensor_type + '/' + name).c_str())
{
availabilityIntf.available(true);
operationalStatusIntf.functional(true);
}
void NsmNumericSensorDbusStatus::updateStatus(bool available, bool functional)
{
availabilityIntf.available(available);
operationalStatusIntf.functional(functional);
}
std::vector<uint8_t> SMBPBIPowerSMBusSensorBytesConverter::convert(double val)
{
std::vector<uint8_t> data(4);
// unit of power is milliwatt in SMBus Sensors and selected unit
// in SensorValue PDI is Watts. Hence it is converted to milliwatts.
auto smbusVal = static_cast<uint32_t>(val * 1000.0);
smbusVal = htole32(smbusVal);
std::memcpy(data.data(), &smbusVal, 4);
return data;
}
std::vector<uint8_t> SMBPBIEnergySMBusSensorBytesConverter::convert(double val)
{
std::vector<uint8_t> data(sizeof(uint64_t));
// unit of energy is millijoules in SMBus Sensors and selected unit
// in SensorValue PDI is Joules. Hence it is converted to millijoules.
auto smbusVal = static_cast<uint64_t>(val * 1000.0);
smbusVal = htole64(smbusVal);
std::memcpy(data.data(), &smbusVal, data.size());
return data;
}
std::vector<uint8_t> SFxP24F8SMBusSensorBytesConverter::convert(double val)
{
std::vector<uint8_t> data(4);
auto smbusVal = static_cast<int32_t>(val * (1 << 8));
smbusVal = htole32(smbusVal);
std::memcpy(data.data(), &smbusVal, 4);
return data;
}
std::vector<uint8_t> Uint64SMBusSensorBytesConverter::convert(double val)
{
std::vector<uint8_t> data(8);
auto smbusVal = static_cast<uint64_t>(val);
smbusVal = htole64(smbusVal);
std::memcpy(data.data(), &smbusVal, 8);
return data;
}
#ifdef NVIDIA_SHMEM
NsmNumericSensorShmem::NsmNumericSensorShmem(
const std::string& name, const std::string& sensor_type,
const std::string& association,
std::unique_ptr<SMBusSensorBytesConverter> smbusSensorBytesConverter) :
objPath("/xyz/openbmc_project/sensors/" + sensor_type + '/' + name),
association(association),
smbusSensorBytesConverter(std::move(smbusSensorBytesConverter))
{
updateReading(std::numeric_limits<double>::quiet_NaN());
}
void NsmNumericSensorShmem::updateReading(double value, uint64_t /*timestamp*/)
{
auto timestamp = static_cast<uint64_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count());
nv::sensor_aggregation::DbusVariantType valueVariant{value};
std::vector<uint8_t> smbusData = smbusSensorBytesConverter->convert(value);
tal::TelemetryAggregator::updateTelemetry(
objPath, valueInterface, valueProperty, smbusData, timestamp, 0,
valueVariant, association);
}
#endif
NsmNumericSensorCompositeChildValue::NsmNumericSensorCompositeChildValue(
const std::string& name, const std::string& sensorType,
const std::vector<std::string>& parents) :
name(name),
sensorType(sensorType), parents(parents)
{}
void NsmNumericSensorCompositeChildValue::updateReading(double value,
uint64_t /*timestamp*/)
{
SensorManager& manager = SensorManager::getInstance();
// Iterate through the parents vector to check if it corresponding sensor is
// created. when all sensors are cached parents container wil be empty
for (auto it = parents.begin(); it != parents.end();)
{
auto sensorIt = manager.objectPathToSensorMap.find(*it);
if (sensorIt != manager.objectPathToSensorMap.end())
{
auto sensor = sensorIt->second;
if (sensor)
{
sensorCache.emplace_back(
std::dynamic_pointer_cast<NsmNumericSensorComposite>(
sensor));
it = parents.erase(it);
continue;
}
}
++it;
}
// update each cached sensor
for (const auto& sensor : sensorCache)
{
sensor->updateCompositeReading(name, value);
}
}
requester::Coroutine NsmNumericSensor::update(SensorManager& manager, eid_t eid)
{
auto requestMsg = genRequestMsg(eid, 0);
if (!requestMsg.has_value())
{
lg2::error(
"NsmNumericSensorComposite::update: genRequestMsg failed, name={NAME}, eid={EID}",
"NAME", getName(), "EID", eid);
co_return NSM_SW_ERROR;
}
#ifdef LTTNG_TRACING
lttng_ust_tracepoint(nsmd, sensor_polling_request_generated, eid,
requestMsg.value().data(), this->getName().c_str());
#endif
std::shared_ptr<const nsm_msg> responseMsg;
size_t responseLen = 0;
auto rc = co_await manager.SendRecvNsmMsg(eid, *requestMsg, responseMsg,
responseLen);
if (rc)
{
for (const auto& sensor : sensorValue->getObjects())
{
sensor->updateReading(std::numeric_limits<double>::quiet_NaN());
}
co_return rc;
}
rc = handleResponseMsg(responseMsg.get(), responseLen);
#ifdef LTTNG_TRACING
lttng_ust_tracepoint(nsmd, dbus_sensor_reading_updated, eid,
responseMsg.get(), this->getName().c_str());
#endif
co_return rc;
}
} // namespace nsm