| /* |
| * 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 |