blob: 5852739799d786b1262257546dee6a7b6304fd2a [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 "nsmDevice.hpp"
#include "common/sleep.hpp"
#include "nsmEvent/nsmFabricManagerStateEvent.hpp"
#include "nsmEvent/nsmLongRunningEventHandler.hpp"
#include "nsmFwSwInventory/GPUSWInventory.hpp"
#include "nsmLongRunning/nsmLongRunningSensor.hpp"
#include "nsmMsgTypesSensor.hpp"
#include "nsmNumericSensor/nsmNumericAggregator.hpp"
#include "sensorManager.hpp"
#include "utils.hpp"
#include <phosphor-logging/lg2.hpp>
namespace nsm
{
std::shared_ptr<NsmNumericAggregator>
NsmDevice::findAggregatorByType([[maybe_unused]] const std::string& type)
{
std::shared_ptr<NsmNumericAggregator> aggregator{};
auto itr =
std::find_if(sensorAggregators.begin(), sensorAggregators.end(),
[&](const auto& e) { return e->getType() == type; });
if (itr != sensorAggregators.end())
{
aggregator = *itr;
}
return aggregator;
}
int parseStaticUuid(uuid_t& uuid, uint8_t& deviceType, uint8_t& instanceNumber,
uint8_t& deviceRole)
{
int n1 = -1;
int n2 = -1;
std::sscanf(uuid.c_str(), "STATIC:%d:%d", &n1, &n2);
if (n1 < 0 || n1 > 0xffff)
{
return -1;
}
if (n2 < 0 || n2 > 0xff)
{
return -2;
}
utils::getDeviceTypeAndRole(n1, &deviceType, &deviceRole);
instanceNumber = n2;
return 0;
}
std::shared_ptr<NsmDevice>
findNsmDeviceByIdentification(NsmDeviceTable& nsmDevices,
uint8_t deviceType, uint8_t instanceNumber,
uint8_t deviceRole)
{
std::shared_ptr<NsmDevice> ret{};
for (auto nsmDevice : nsmDevices)
{
if (nsmDevice->getDeviceType() == deviceType &&
nsmDevice->getInstanceNumber() == instanceNumber &&
nsmDevice->getDeviceRole() == deviceRole)
{
ret = nsmDevice;
break;
}
}
return ret;
}
std::shared_ptr<NsmDevice> findNsmDeviceByUUID(NsmDeviceTable& nsmDevices,
const uuid_t& uuid)
{
std::shared_ptr<NsmDevice> ret{};
for (auto nsmDevice : nsmDevices)
{
if ((nsmDevice->uuid).substr(0, UUID_LEN) == uuid.substr(0, UUID_LEN))
{
ret = nsmDevice;
break;
}
}
return ret;
}
void NsmDevice::setEventMode(uint8_t mode)
{
if (mode > GLOBAL_EVENT_GENERATION_ENABLE_PUSH)
{
lg2::debug("event generation setting: invalid value={SETTING} provided",
"SETTING", mode);
return;
}
eventMode = mode;
}
uint8_t NsmDevice::getEventMode()
{
return eventMode;
}
bool NsmDevice::isCommandSupported(uint8_t messageType, uint8_t commandCode)
{
bool supported = false;
if (messageTypesToCommandCodeMatrix[messageType][commandCode])
{
supported = true;
}
return supported;
}
void NsmDevice::addSensorBase(const std::shared_ptr<NsmObject>& sensor,
PollingType pollingType)
{
sensor->deviceIdentifier =
utils::getDeviceInstanceName(getDeviceType(), getInstanceNumber());
deviceSensors.push_back(sensor);
switch (pollingType)
{
case PollingType::Priority:
prioritySensors.push_back(sensor);
break;
case PollingType::GpuPerformanceMonitoring:
sensor->refreshLimitInUsec = DEFAULT_GPM_REFRESH_LIMIT_IN_USEC;
roundRobinSensors.push_back(sensor);
break;
case PollingType::Static:
std::const_pointer_cast<NsmObject>(sensor)->isStatic = true;
roundRobinSensors.push_back(sensor);
break;
case PollingType::LongRunning:
longRunningSensors.push_back(sensor);
break;
case PollingType::RoundRobin:
default:
roundRobinSensors.push_back(sensor);
break;
}
}
requester::Coroutine NsmDevice::setOnline()
{
isDeviceActive = true;
lg2::info(
"NSMDevice: deviceType:{DEVTYPE} InstanceNumber:{INSTNUM} gets online",
"DEVTYPE", getDeviceType(), "INSTNUM", getInstanceNumber());
isDeviceReady = false;
NsmServiceReadyIntf::getInstance().setStateStarting();
uint32_t count = 0;
for (auto sensor : roundRobinSensors)
{
// Mark all the sensors as unrefreshed.
sensor->isRefreshed = false;
count++;
if (count == MAX_SENSOR_UPDATE_BATCH_SIZE)
{
co_await common::Sleep(event.get(), 10000, common::NonPriority);
count = 0;
}
}
co_return NSM_SW_SUCCESS;
}
requester::Coroutine NsmDevice::setOffline()
{
isDeviceActive = false;
if (gpudriverSensor)
{
lg2::info(
"Setting GPU driver state to unknown as eid = {EID} gets offline",
"EID", eid);
gpudriverSensor->driverState = 0;
}
lg2::info(
"NSMDevice: deviceType:{DEVTYPE} InstanceNumber:{INSTNUM} gets offline",
"DEVTYPE", getDeviceType(), "INSTNUM", getInstanceNumber());
size_t sensorIndex{0};
auto& sensors = deviceSensors;
while (sensorIndex < sensors.size())
{
uint32_t count = 0;
while (count < MAX_SENSOR_UPDATE_BATCH_SIZE &&
sensorIndex < sensors.size())
{
auto sensor = sensors[sensorIndex];
sensor->handleOfflineState();
++sensorIndex;
++count;
}
co_await common::Sleep(event.get(), 10000, common::NonPriority);
}
// coverity[missing_return]
co_return NSM_SW_SUCCESS;
}
NsmLongRunningEventHandler& NsmDevice::registerLongRunningEventHandler()
{
auto longRunningEventHandler =
std::make_shared<NsmLongRunningEventHandler>();
deviceEvents.emplace_back(longRunningEventHandler);
eventDispatcher.addEvent(NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY,
NSM_LONG_RUNNING_EVENT, longRunningEventHandler);
return *longRunningEventHandler;
}
void NsmDevice::registerLongRunningHandler(
uint8_t messageType, uint8_t commandCode,
std::shared_ptr<NsmLongRunningEvent> sensorInstance)
{
clearLongRunningHandler();
longRunningHandler = ActiveLongRunningHandlerInfo{messageType, commandCode,
sensorInstance};
}
void NsmDevice::clearLongRunningHandler()
{
if (!longRunningHandler.has_value())
{
return;
}
longRunningHandler.reset();
}
std::optional<ActiveLongRunningHandlerInfo>
NsmDevice::getActiveLongRunningHandler() const
{
return longRunningHandler;
}
int NsmDevice::invokeLongRunningHandler(eid_t eid, NsmType type,
NsmEventId eventId,
const nsm_msg* event, size_t eventLen)
{
if (shouldLog("NsmDevice::invokeLongRunningHandler",
!longRunningHandler.has_value()))
{
lg2::error(
"NsmDevice::invokeLongRunningHandler: No active handler registered for long-running event, EID={EID}",
"EID", eid);
}
if (!longRunningHandler.has_value())
{
return NSM_SW_ERROR_DATA;
}
uint16_t eventState = 0;
uint8_t dataSize = 0;
auto rc = decode_nsm_event(event, eventLen, eventId,
NSM_NVIDIA_GENERAL_EVENT_CLASS, &eventState,
&dataSize);
if (shouldLog("decode_nsm_event", nsm_sw_codes(rc)))
{
lg2::error(
"NsmLongRunningEventHandler : Failed to decode long running event state : EID={EID}",
"EID", eid);
}
if (rc != NSM_SW_SUCCESS)
{
return rc;
}
nsm_long_running_event_state state{};
memcpy(&state, &eventState, sizeof(uint16_t));
const auto& [messageType, commandCode,
sensorInstance] = *longRunningHandler;
if (state.nvidia_message_type != messageType ||
state.command != commandCode)
{
lg2::error(
"NsmDevice::invokeLongRunningHandler: Mismatched message type or command code, "
"Expected MessageType={EXPECTED_MSG_TYPE}, Received MessageType={RECEIVED_MSG_TYPE}, "
"Expected CommandCode={EXPECTED_COMMAND_CODE}, Received CommandCode={RECEIVED_COMMAND_CODE}, EID={EID}",
"EXPECTED_MSG_TYPE", messageType, "RECEIVED_MSG_TYPE",
uint8_t(state.nvidia_message_type), "EXPECTED_COMMAND_CODE",
commandCode, "RECEIVED_COMMAND_CODE", uint8_t(state.command), "EID",
eid);
return NSM_SW_ERROR_DATA;
}
// Call the `handle` method directly on the instance
return sensorInstance->handle(eid, type, eventId, event, eventLen);
}
void NsmDevice::initMsgTypesSensor()
{
msgTypesSensor = std::make_shared<NsmMsgTypes>(
"Supported Message Types", "NSM_NVIDIA_MESSAGE_TYPE", *this);
addSensor(msgTypesSensor, false);
}
// FruInterfaceManager method implementations
bool FruInterfaceManager::needsRecreation(
const std::set<std::string>& newProperties) const
{
return !initialized || (supportedProperties != newProperties);
}
void FruInterfaceManager::markInitialized(
const std::set<std::string>& properties)
{
supportedProperties = properties;
initialized = true;
}
bool FruInterfaceManager::isPropertySupported(
const std::string& propertyName) const
{
return supportedProperties.find(propertyName) != supportedProperties.end();
}
void FruInterfaceManager::reset()
{
interface.reset();
supportedProperties.clear();
initialized = false;
}
void FruInterfaceManager::createAndRegisterInterface(
sdbusplus::asio::object_server& objServer, uint8_t eid,
std::shared_ptr<NsmDevice> nsmDevice, const InventoryProperties& properties,
const std::multimap<uuid_t, std::tuple<eid_t, MctpMedium, MctpBinding>>&
eidTable)
{
std::string objPath = "/xyz/openbmc_project/FruDevice/" +
std::to_string(eid);
interface = objServer.add_unique_interface(objPath,
"xyz.openbmc_project.FruDevice");
registerAllProperties(nsmDevice, properties, eidTable);
interface->initialize();
}
void FruInterfaceManager::updateAllPropertyValues(
std::shared_ptr<NsmDevice> nsmDevice, const InventoryProperties& properties,
const std::multimap<uuid_t, std::tuple<eid_t, MctpMedium, MctpBinding>>&
eidTable)
{
if (!interface)
return;
if (properties.find(BOARD_PART_NUMBER) != properties.end())
{
interface->set_property(
"BOARD_PART_NUMBER",
std::get<std::string>(properties.at(BOARD_PART_NUMBER)));
}
if (properties.find(FRU_PART_NUMBER) != properties.end())
{
interface->set_property(
"FRU_PART_NUMBER",
std::get<std::string>(properties.at(FRU_PART_NUMBER)));
}
if (properties.find(SERIAL_NUMBER) != properties.end())
{
interface->set_property(
"SERIAL_NUMBER",
std::get<std::string>(properties.at(SERIAL_NUMBER)));
}
if (properties.find(MARKETING_NAME) != properties.end())
{
interface->set_property(
"MARKETING_NAME",
std::get<std::string>(properties.at(MARKETING_NAME)));
}
if (properties.find(BUILD_DATE) != properties.end())
{
interface->set_property(
"BUILD_DATE", std::get<std::string>(properties.at(BUILD_DATE)));
}
auto mctpUuid = utils::getUUIDFromEID(eidTable, nsmDevice->eid);
if (mctpUuid.has_value())
{
nsmDevice->uuid = *mctpUuid;
}
if (properties.find(DEVICE_GUID) != properties.end())
{
interface->set_property("DEVICE_UUID",
std::get<uuid_t>(properties.at(DEVICE_GUID)));
nsmDevice->deviceUuid = std::get<uuid_t>(properties.at(DEVICE_GUID));
}
interface->set_property("DEVICE_TYPE", nsmDevice->getDeviceType());
interface->set_property("INSTANCE_NUMBER", nsmDevice->getInstanceNumber());
interface->set_property("UUID", nsmDevice->uuid);
}
void FruInterfaceManager::registerAllProperties(
std::shared_ptr<NsmDevice> nsmDevice, const InventoryProperties& properties,
const std::multimap<uuid_t, std::tuple<eid_t, MctpMedium, MctpBinding>>&
eidTable)
{
if (properties.find(BOARD_PART_NUMBER) != properties.end())
{
interface->register_property(
"BOARD_PART_NUMBER",
std::get<std::string>(properties.at(BOARD_PART_NUMBER)));
}
if (properties.find(FRU_PART_NUMBER) != properties.end())
{
interface->register_property(
"FRU_PART_NUMBER",
std::get<std::string>(properties.at(FRU_PART_NUMBER)));
}
if (properties.find(SERIAL_NUMBER) != properties.end())
{
interface->register_property(
"SERIAL_NUMBER",
std::get<std::string>(properties.at(SERIAL_NUMBER)));
}
if (properties.find(MARKETING_NAME) != properties.end())
{
interface->register_property(
"MARKETING_NAME",
std::get<std::string>(properties.at(MARKETING_NAME)));
}
if (properties.find(BUILD_DATE) != properties.end())
{
interface->register_property(
"BUILD_DATE", std::get<std::string>(properties.at(BUILD_DATE)));
}
auto mctpUuid = utils::getUUIDFromEID(eidTable, nsmDevice->eid);
if (mctpUuid.has_value())
{
nsmDevice->uuid = *mctpUuid;
}
if (properties.find(DEVICE_GUID) != properties.end())
{
interface->register_property(
"DEVICE_UUID", std::get<uuid_t>(properties.at(DEVICE_GUID)));
nsmDevice->deviceUuid = std::get<uuid_t>(properties.at(DEVICE_GUID));
}
interface->register_property("DEVICE_TYPE", nsmDevice->getDeviceType());
interface->register_property("INSTANCE_NUMBER",
nsmDevice->getInstanceNumber());
interface->register_property("UUID", nsmDevice->uuid);
}
} // namespace nsm