From c99a08bea89e52dfa3eeae359750f922051de14a Mon Sep 17 00:00:00 2001 From: "Kumar, Shubham" Date: Tue, 16 May 2023 11:18:01 +0000 Subject: [PATCH] feature: Support for Fan module using zesinint on windows Added ULTs for Fan module in new sysman implementation Added support for Fan in zello_sysman Related-To: LOCI-4409, LOCI-4412 Signed-off-by: Kumar, Shubham --- level_zero/api/sysman/zes_handles_struct.h | 4 + .../api/sysman/zes_sysman_api_entrypoints.h | 42 ++- level_zero/sysman/source/fan/CMakeLists.txt | 17 + .../sysman/source/fan/linux/CMakeLists.txt | 15 + .../source/fan/linux/sysman_os_fan_imp.cpp | 52 +++ .../source/fan/linux/sysman_os_fan_imp.h | 32 ++ level_zero/sysman/source/fan/sysman_fan.cpp | 45 +++ level_zero/sysman/source/fan/sysman_fan.h | 50 +++ .../sysman/source/fan/sysman_fan_imp.cpp | 55 ++++ level_zero/sysman/source/fan/sysman_fan_imp.h | 33 ++ level_zero/sysman/source/fan/sysman_os_fan.h | 32 ++ .../sysman/source/fan/windows/CMakeLists.txt | 14 + .../source/fan/windows/sysman_os_fan_imp.cpp | 228 ++++++++++++++ .../source/fan/windows/sysman_os_fan_imp.h | 42 +++ level_zero/sysman/source/sysman_device.cpp | 5 + level_zero/sysman/source/sysman_device.h | 3 + .../sysman/source/sysman_device_imp.cpp | 7 + level_zero/sysman/source/sysman_device_imp.h | 2 + .../unit_tests/sources/fan/CMakeLists.txt | 11 + .../sources/fan/linux/CMakeLists.txt | 13 + .../sources/fan/linux/test_zes_fan.cpp | 110 +++++++ .../sources/fan/windows/CMakeLists.txt | 14 + .../unit_tests/sources/fan/windows/mock_fan.h | 103 ++++++ .../fan/windows/test_zes_sysman_fan.cpp | 296 ++++++++++++++++++ level_zero/tools/source/sysman/fan/fan.h | 5 +- .../test/black_box_tests/zello_sysman.cpp | 79 ++++- 26 files changed, 1296 insertions(+), 13 deletions(-) create mode 100644 level_zero/sysman/source/fan/CMakeLists.txt create mode 100644 level_zero/sysman/source/fan/linux/CMakeLists.txt create mode 100644 level_zero/sysman/source/fan/linux/sysman_os_fan_imp.cpp create mode 100644 level_zero/sysman/source/fan/linux/sysman_os_fan_imp.h create mode 100644 level_zero/sysman/source/fan/sysman_fan.cpp create mode 100644 level_zero/sysman/source/fan/sysman_fan.h create mode 100644 level_zero/sysman/source/fan/sysman_fan_imp.cpp create mode 100644 level_zero/sysman/source/fan/sysman_fan_imp.h create mode 100644 level_zero/sysman/source/fan/sysman_os_fan.h create mode 100644 level_zero/sysman/source/fan/windows/CMakeLists.txt create mode 100644 level_zero/sysman/source/fan/windows/sysman_os_fan_imp.cpp create mode 100644 level_zero/sysman/source/fan/windows/sysman_os_fan_imp.h create mode 100644 level_zero/sysman/test/unit_tests/sources/fan/CMakeLists.txt create mode 100644 level_zero/sysman/test/unit_tests/sources/fan/linux/CMakeLists.txt create mode 100644 level_zero/sysman/test/unit_tests/sources/fan/linux/test_zes_fan.cpp create mode 100644 level_zero/sysman/test/unit_tests/sources/fan/windows/CMakeLists.txt create mode 100644 level_zero/sysman/test/unit_tests/sources/fan/windows/mock_fan.h create mode 100644 level_zero/sysman/test/unit_tests/sources/fan/windows/test_zes_sysman_fan.cpp diff --git a/level_zero/api/sysman/zes_handles_struct.h b/level_zero/api/sysman/zes_handles_struct.h index 87f589cbea..0d0eb958a6 100644 --- a/level_zero/api/sysman/zes_handles_struct.h +++ b/level_zero/api/sysman/zes_handles_struct.h @@ -54,3 +54,7 @@ struct _zes_temp_handle_t { struct _zes_perf_handle_t { virtual ~_zes_perf_handle_t() = default; }; + +struct _zes_fan_handle_t { + virtual ~_zes_fan_handle_t() = default; +}; \ No newline at end of file diff --git a/level_zero/api/sysman/zes_sysman_api_entrypoints.h b/level_zero/api/sysman/zes_sysman_api_entrypoints.h index 0424ffecc1..ac3ce74028 100644 --- a/level_zero/api/sysman/zes_sysman_api_entrypoints.h +++ b/level_zero/api/sysman/zes_sysman_api_entrypoints.h @@ -790,43 +790,71 @@ ze_result_t zesDeviceEnumFans( zes_device_handle_t hDevice, uint32_t *pCount, zes_fan_handle_t *phFan) { - return L0::SysmanDevice::fanGet(hDevice, pCount, phFan); + if (L0::sysmanInitFromCore) { + return L0::SysmanDevice::fanGet(hDevice, pCount, phFan); + } else { + return L0::Sysman::SysmanDevice::fanGet(hDevice, pCount, phFan); + } } ze_result_t zesFanGetProperties( zes_fan_handle_t hFan, zes_fan_properties_t *pProperties) { - return L0::Fan::fromHandle(hFan)->fanGetProperties(pProperties); + if (L0::sysmanInitFromCore) { + return L0::Fan::fromHandle(hFan)->fanGetProperties(pProperties); + } else { + return L0::Sysman::Fan::fromHandle(hFan)->fanGetProperties(pProperties); + } } ze_result_t zesFanGetConfig( zes_fan_handle_t hFan, zes_fan_config_t *pConfig) { - return L0::Fan::fromHandle(hFan)->fanGetConfig(pConfig); + if (L0::sysmanInitFromCore) { + return L0::Fan::fromHandle(hFan)->fanGetConfig(pConfig); + } else { + return L0::Sysman::Fan::fromHandle(hFan)->fanGetConfig(pConfig); + } } ze_result_t zesFanSetDefaultMode( zes_fan_handle_t hFan) { - return L0::Fan::fromHandle(hFan)->fanSetDefaultMode(); + if (L0::sysmanInitFromCore) { + return L0::Fan::fromHandle(hFan)->fanSetDefaultMode(); + } else { + return L0::Sysman::Fan::fromHandle(hFan)->fanSetDefaultMode(); + } } ze_result_t zesFanSetFixedSpeedMode( zes_fan_handle_t hFan, const zes_fan_speed_t *speed) { - return L0::Fan::fromHandle(hFan)->fanSetFixedSpeedMode(speed); + if (L0::sysmanInitFromCore) { + return L0::Fan::fromHandle(hFan)->fanSetFixedSpeedMode(speed); + } else { + return L0::Sysman::Fan::fromHandle(hFan)->fanSetFixedSpeedMode(speed); + } } ze_result_t zesFanSetSpeedTableMode( zes_fan_handle_t hFan, const zes_fan_speed_table_t *speedTable) { - return L0::Fan::fromHandle(hFan)->fanSetSpeedTableMode(speedTable); + if (L0::sysmanInitFromCore) { + return L0::Fan::fromHandle(hFan)->fanSetSpeedTableMode(speedTable); + } else { + return L0::Sysman::Fan::fromHandle(hFan)->fanSetSpeedTableMode(speedTable); + } } ze_result_t zesFanGetState( zes_fan_handle_t hFan, zes_fan_speed_units_t units, int32_t *pSpeed) { - return L0::Fan::fromHandle(hFan)->fanGetState(units, pSpeed); + if (L0::sysmanInitFromCore) { + return L0::Fan::fromHandle(hFan)->fanGetState(units, pSpeed); + } else { + return L0::Sysman::Fan::fromHandle(hFan)->fanGetState(units, pSpeed); + } } ze_result_t zesDeviceEnumLeds( diff --git a/level_zero/sysman/source/fan/CMakeLists.txt b/level_zero/sysman/source/fan/CMakeLists.txt new file mode 100644 index 0000000000..4c365eec95 --- /dev/null +++ b/level_zero/sysman/source/fan/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Copyright (C) 2023 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +target_sources(${L0_STATIC_LIB_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/sysman_fan.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sysman_fan.h + ${CMAKE_CURRENT_SOURCE_DIR}/sysman_fan_imp.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sysman_fan_imp.h + ${CMAKE_CURRENT_SOURCE_DIR}/sysman_os_fan.h +) + +add_subdirectories() diff --git a/level_zero/sysman/source/fan/linux/CMakeLists.txt b/level_zero/sysman/source/fan/linux/CMakeLists.txt new file mode 100644 index 0000000000..3b1ac4a207 --- /dev/null +++ b/level_zero/sysman/source/fan/linux/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Copyright (C) 2023 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +if(UNIX) + target_sources(${L0_STATIC_LIB_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/sysman_os_fan_imp.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sysman_os_fan_imp.h + ) +endif() + diff --git a/level_zero/sysman/source/fan/linux/sysman_os_fan_imp.cpp b/level_zero/sysman/source/fan/linux/sysman_os_fan_imp.cpp new file mode 100644 index 0000000000..d498efd48c --- /dev/null +++ b/level_zero/sysman/source/fan/linux/sysman_os_fan_imp.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/source/fan/linux/sysman_os_fan_imp.h" + +#include "level_zero/sysman/source/linux/pmt/sysman_pmt.h" +#include "level_zero/sysman/source/linux/zes_os_sysman_imp.h" + +namespace L0 { +namespace Sysman { + +ze_result_t LinuxFanImp::getProperties(zes_fan_properties_t *pProperties) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; +} +ze_result_t LinuxFanImp::getConfig(zes_fan_config_t *pConfig) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + +ze_result_t LinuxFanImp::setDefaultMode() { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + +ze_result_t LinuxFanImp::setFixedSpeedMode(const zes_fan_speed_t *pSpeed) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + +ze_result_t LinuxFanImp::setSpeedTableMode(const zes_fan_speed_table_t *pSpeedTable) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + +ze_result_t LinuxFanImp::getState(zes_fan_speed_units_t units, int32_t *pSpeed) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + +bool LinuxFanImp::isFanModuleSupported() { + return false; +} + +LinuxFanImp::LinuxFanImp(OsSysman *pOsSysman) { +} + +std::unique_ptr OsFan::create(OsSysman *pOsSysman) { + std::unique_ptr pLinuxFanImp = std::make_unique(pOsSysman); + return pLinuxFanImp; +} + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/fan/linux/sysman_os_fan_imp.h b/level_zero/sysman/source/fan/linux/sysman_os_fan_imp.h new file mode 100644 index 0000000000..6ed946314c --- /dev/null +++ b/level_zero/sysman/source/fan/linux/sysman_os_fan_imp.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "shared/source/helpers/non_copyable_or_moveable.h" + +#include "level_zero/sysman/source/fan/sysman_os_fan.h" + +namespace L0 { +namespace Sysman { + +class SysfsAccess; + +class LinuxFanImp : public OsFan, NEO::NonCopyableOrMovableClass { + public: + ze_result_t getProperties(zes_fan_properties_t *pProperties) override; + ze_result_t getConfig(zes_fan_config_t *pConfig) override; + ze_result_t setDefaultMode() override; + ze_result_t setFixedSpeedMode(const zes_fan_speed_t *pSpeed) override; + ze_result_t setSpeedTableMode(const zes_fan_speed_table_t *pSpeedTable) override; + ze_result_t getState(zes_fan_speed_units_t units, int32_t *pSpeed) override; + bool isFanModuleSupported() override; + LinuxFanImp(OsSysman *pOsSysman); + LinuxFanImp() = default; + ~LinuxFanImp() override = default; +}; +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/fan/sysman_fan.cpp b/level_zero/sysman/source/fan/sysman_fan.cpp new file mode 100644 index 0000000000..2f93a6771c --- /dev/null +++ b/level_zero/sysman/source/fan/sysman_fan.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/source/fan/sysman_fan.h" + +#include "shared/source/helpers/basic_math.h" + +#include "level_zero/sysman/source/fan/sysman_fan_imp.h" + +namespace L0 { +namespace Sysman { + +FanHandleContext::~FanHandleContext() = default; + +void FanHandleContext::init() { + std::unique_ptr pFan = std::make_unique(pOsSysman); + if (pFan->initSuccess == true) { + handleList.push_back(std::move(pFan)); + } +} + +ze_result_t FanHandleContext::fanGet(uint32_t *pCount, zes_fan_handle_t *phFan) { + std::call_once(initFanOnce, [this]() { + this->init(); + }); + uint32_t handleListSize = static_cast(handleList.size()); + if (0 == *pCount) { + *pCount = handleListSize; + return ZE_RESULT_SUCCESS; + } + *pCount = std::min(*pCount, handleListSize); + if (nullptr != phFan) { + for (uint32_t i = 0; i < *pCount; i++) { + phFan[i] = handleList[i]->toHandle(); + } + } + return ZE_RESULT_SUCCESS; +} + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/fan/sysman_fan.h b/level_zero/sysman/source/fan/sysman_fan.h new file mode 100644 index 0000000000..ce15688acc --- /dev/null +++ b/level_zero/sysman/source/fan/sysman_fan.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "level_zero/api/sysman/zes_handles_struct.h" +#include + +#include +#include +#include + +namespace L0 { +namespace Sysman { +struct OsSysman; +class Fan : _zes_fan_handle_t { + public: + virtual ze_result_t fanGetProperties(zes_fan_properties_t *pProperties) = 0; + virtual ze_result_t fanGetConfig(zes_fan_config_t *pConfig) = 0; + virtual ze_result_t fanSetDefaultMode() = 0; + virtual ze_result_t fanSetFixedSpeedMode(const zes_fan_speed_t *pSpeed) = 0; + virtual ze_result_t fanSetSpeedTableMode(const zes_fan_speed_table_t *pSpeedTable) = 0; + virtual ze_result_t fanGetState(zes_fan_speed_units_t units, int32_t *pSpeed) = 0; + + static Fan *fromHandle(zes_fan_handle_t handle) { + return static_cast(handle); + } + inline zes_fan_handle_t toHandle() { return this; } + bool initSuccess = false; +}; +struct FanHandleContext { + FanHandleContext(OsSysman *pOsSysman) : pOsSysman(pOsSysman){}; + ~FanHandleContext(); + + void init(); + + ze_result_t fanGet(uint32_t *pCount, zes_fan_handle_t *phFan); + + OsSysman *pOsSysman = nullptr; + std::vector> handleList = {}; + + private: + std::once_flag initFanOnce; +}; + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/fan/sysman_fan_imp.cpp b/level_zero/sysman/source/fan/sysman_fan_imp.cpp new file mode 100644 index 0000000000..b7658b9f80 --- /dev/null +++ b/level_zero/sysman/source/fan/sysman_fan_imp.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/source/fan/sysman_fan_imp.h" + +#include "shared/source/helpers/debug_helpers.h" + +namespace L0 { +namespace Sysman { + +FanImp::FanImp(OsSysman *pOsSysman) { + pOsFan = OsFan::create(pOsSysman); + UNRECOVERABLE_IF(nullptr == pOsFan); + + init(); +} + +ze_result_t FanImp::fanGetProperties(zes_fan_properties_t *pProperties) { + return pOsFan->getProperties(pProperties); +} + +ze_result_t FanImp::fanGetConfig(zes_fan_config_t *pConfig) { + return pOsFan->getConfig(pConfig); +} + +ze_result_t FanImp::fanSetDefaultMode() { + return pOsFan->setDefaultMode(); +} + +ze_result_t FanImp::fanSetFixedSpeedMode(const zes_fan_speed_t *pSpeed) { + return pOsFan->setFixedSpeedMode(pSpeed); +} + +ze_result_t FanImp::fanSetSpeedTableMode(const zes_fan_speed_table_t *pSpeedTable) { + return pOsFan->setSpeedTableMode(pSpeedTable); +} + +ze_result_t FanImp::fanGetState(zes_fan_speed_units_t units, int32_t *pSpeed) { + return pOsFan->getState(units, pSpeed); +} + +void FanImp::init() { + if (pOsFan->isFanModuleSupported()) { + this->initSuccess = true; + } +} + +FanImp::~FanImp() = default; + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/fan/sysman_fan_imp.h b/level_zero/sysman/source/fan/sysman_fan_imp.h new file mode 100644 index 0000000000..0f128ce5f3 --- /dev/null +++ b/level_zero/sysman/source/fan/sysman_fan_imp.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "shared/source/helpers/non_copyable_or_moveable.h" + +#include "level_zero/sysman/source/fan/sysman_fan.h" +#include "level_zero/sysman/source/fan/sysman_os_fan.h" + +namespace L0 { +namespace Sysman { +class FanImp : public Fan, NEO::NonCopyableOrMovableClass { + public: + ze_result_t fanGetProperties(zes_fan_properties_t *pProperties) override; + ze_result_t fanGetConfig(zes_fan_config_t *pConfig) override; + ze_result_t fanSetDefaultMode() override; + ze_result_t fanSetFixedSpeedMode(const zes_fan_speed_t *pSpeed) override; + ze_result_t fanSetSpeedTableMode(const zes_fan_speed_table_t *pSpeedTable) override; + ze_result_t fanGetState(zes_fan_speed_units_t units, int32_t *pSpeed) override; + FanImp() = default; + FanImp(OsSysman *pOsSysman); + ~FanImp() override; + + std::unique_ptr pOsFan; + void init(); +}; +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/fan/sysman_os_fan.h b/level_zero/sysman/source/fan/sysman_os_fan.h new file mode 100644 index 0000000000..557c60ba64 --- /dev/null +++ b/level_zero/sysman/source/fan/sysman_os_fan.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include + +#include + +namespace L0 { +namespace Sysman { + +struct OsSysman; +class OsFan { + public: + virtual ze_result_t getProperties(zes_fan_properties_t *pProperties) = 0; + virtual ze_result_t getConfig(zes_fan_config_t *pConfig) = 0; + virtual ze_result_t setDefaultMode() = 0; + virtual ze_result_t setFixedSpeedMode(const zes_fan_speed_t *pSpeed) = 0; + virtual ze_result_t setSpeedTableMode(const zes_fan_speed_table_t *pSpeedTable) = 0; + virtual ze_result_t getState(zes_fan_speed_units_t units, int32_t *pSpeed) = 0; + virtual bool isFanModuleSupported() = 0; + static std::unique_ptr create(OsSysman *pOsSysman); + virtual ~OsFan() = default; +}; + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/fan/windows/CMakeLists.txt b/level_zero/sysman/source/fan/windows/CMakeLists.txt new file mode 100644 index 0000000000..01128f7d50 --- /dev/null +++ b/level_zero/sysman/source/fan/windows/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# Copyright (C) 2023 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +if(WIN32) + target_sources(${L0_STATIC_LIB_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/sysman_os_fan_imp.h + ${CMAKE_CURRENT_SOURCE_DIR}/sysman_os_fan_imp.cpp + ) +endif() diff --git a/level_zero/sysman/source/fan/windows/sysman_os_fan_imp.cpp b/level_zero/sysman/source/fan/windows/sysman_os_fan_imp.cpp new file mode 100644 index 0000000000..1deb9e7bcd --- /dev/null +++ b/level_zero/sysman/source/fan/windows/sysman_os_fan_imp.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/source/fan/windows/sysman_os_fan_imp.h" + +#include "level_zero/sysman/source/windows/sysman_kmd_sys_manager.h" + +namespace L0 { +namespace Sysman { + +struct FanPoint { + union { + struct { + int32_t temperatureDegreesCelsius : 16; + int32_t fanSpeedPercent : 16; + }; + int32_t data; + }; +}; + +ze_result_t WddmFanImp::getProperties(zes_fan_properties_t *pProperties) { + pProperties->onSubdevice = false; + pProperties->subdeviceId = 0; + + std::vector vRequests = {}; + std::vector vResponses = {}; + KmdSysman::RequestProperty request = {}; + + request.commandId = KmdSysman::Command::Set; + request.componentId = KmdSysman::Component::FanComponent; + request.requestId = KmdSysman::Requests::Fans::CurrentNumOfControlPoints; + request.dataSize = sizeof(uint32_t); + + uint32_t FanPoints = 2; + memcpy_s(request.dataBuffer, sizeof(uint32_t), &FanPoints, sizeof(uint32_t)); + + vRequests.push_back(request); + + request.dataSize = 0; + memset(request.dataBuffer, request.dataSize, sizeof(request.dataBuffer)); + request.commandId = KmdSysman::Command::Get; + request.requestId = KmdSysman::Requests::Fans::MaxFanControlPointsSupported; + + vRequests.push_back(request); + + ze_result_t status = pKmdSysManager->requestMultiple(vRequests, vResponses); + + if ((status != ZE_RESULT_SUCCESS) || (vResponses.size() != vRequests.size())) { + return status; + } + + pProperties->canControl = (vResponses[0].returnCode == KmdSysman::Success); + + if (vResponses[1].returnCode == KmdSysman::Success) { + memcpy_s(&FanPoints, sizeof(uint32_t), vResponses[1].dataBuffer, sizeof(uint32_t)); + pProperties->maxPoints = maxPoints = static_cast(FanPoints); + } + pProperties->maxRPM = -1; + pProperties->supportedModes = zes_fan_speed_mode_t::ZES_FAN_SPEED_MODE_TABLE; + pProperties->supportedUnits = zes_fan_speed_units_t::ZES_FAN_SPEED_UNITS_PERCENT; + + return ZE_RESULT_SUCCESS; +} + +ze_result_t WddmFanImp::getConfig(zes_fan_config_t *pConfig) { + KmdSysman::RequestProperty request; + KmdSysman::ResponseProperty response; + + request.commandId = KmdSysman::Command::Get; + request.componentId = KmdSysman::Component::FanComponent; + request.requestId = KmdSysman::Requests::Fans::CurrentNumOfControlPoints; + + ze_result_t status = pKmdSysManager->requestSingle(request, response); + + if (status != ZE_RESULT_SUCCESS) { + return status; + } else { + uint32_t value = 0; + memcpy_s(&value, sizeof(uint32_t), response.dataBuffer, sizeof(uint32_t)); + if (value == 0) { + pConfig->mode = ZES_FAN_SPEED_MODE_DEFAULT; + } else { + pConfig->mode = ZES_FAN_SPEED_MODE_TABLE; + pConfig->speedTable.numPoints = value; + + request.requestId = KmdSysman::Requests::Fans::CurrentFanPoint; + + for (int32_t i = 0; i < pConfig->speedTable.numPoints; i++) { + if (pKmdSysManager->requestSingle(request, response) == ZE_RESULT_SUCCESS) { + + FanPoint point = {}; + memcpy_s(&point.data, sizeof(uint32_t), response.dataBuffer, sizeof(uint32_t)); + + pConfig->speedTable.table[i].speed.speed = point.fanSpeedPercent; + pConfig->speedTable.table[i].speed.units = ZES_FAN_SPEED_UNITS_PERCENT; + pConfig->speedTable.table[i].temperature = point.temperatureDegreesCelsius; + } + } + } + } + + return ZE_RESULT_SUCCESS; +} + +ze_result_t WddmFanImp::setDefaultMode() { + KmdSysman::RequestProperty request; + KmdSysman::ResponseProperty response; + + // Passing current number of control points as zero will reset pcode to default fan curve + uint32_t value = 0; // 0 to reset to default + request.commandId = KmdSysman::Command::Set; + request.componentId = KmdSysman::Component::FanComponent; + request.requestId = KmdSysman::Requests::Fans::CurrentNumOfControlPoints; + request.dataSize = sizeof(uint32_t); + memcpy_s(request.dataBuffer, sizeof(uint32_t), &value, sizeof(uint32_t)); + + return pKmdSysManager->requestSingle(request, response); +} + +ze_result_t WddmFanImp::setFixedSpeedMode(const zes_fan_speed_t *pSpeed) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + +ze_result_t WddmFanImp::setSpeedTableMode(const zes_fan_speed_table_t *pSpeedTable) { + + KmdSysman::RequestProperty singleRequest; + KmdSysman::ResponseProperty singleResponse; + singleRequest.commandId = KmdSysman::Command::Get; + singleRequest.componentId = KmdSysman::Component::FanComponent; + singleRequest.requestId = KmdSysman::Requests::Fans::MaxFanControlPointsSupported; + uint32_t FanPoints = 2; + + if (pKmdSysManager->requestSingle(singleRequest, singleResponse) == ZE_RESULT_SUCCESS) { + if (singleResponse.returnCode == KmdSysman::Success) { + memcpy_s(&FanPoints, sizeof(uint32_t), singleResponse.dataBuffer, sizeof(uint32_t)); + } + maxPoints = static_cast(FanPoints); + } + + if (pSpeedTable->numPoints == 0 || pSpeedTable->numPoints > maxPoints) { + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + } + + for (int32_t i = 0; i < pSpeedTable->numPoints; i++) { + if (pSpeedTable->table[i].speed.units == zes_fan_speed_units_t::ZES_FAN_SPEED_UNITS_RPM) { + return ze_result_t::ZE_RESULT_ERROR_INVALID_ARGUMENT; + } + } + + std::vector vRequests = {}; + std::vector vResponses = {}; + KmdSysman::RequestProperty request = {}; + + uint32_t value = pSpeedTable->numPoints; + + request.commandId = KmdSysman::Command::Set; + request.componentId = KmdSysman::Component::FanComponent; + request.requestId = KmdSysman::Requests::Fans::CurrentNumOfControlPoints; + request.dataSize = sizeof(uint32_t); + memcpy_s(request.dataBuffer, sizeof(uint32_t), &value, sizeof(uint32_t)); + vRequests.push_back(request); + + request.requestId = KmdSysman::Requests::Fans::CurrentFanPoint; + for (int32_t i = 0; i < pSpeedTable->numPoints; i++) { + FanPoint point = {}; + point.fanSpeedPercent = pSpeedTable->table[i].speed.speed; + point.temperatureDegreesCelsius = pSpeedTable->table[i].temperature; + value = point.data; + memcpy_s(request.dataBuffer, sizeof(uint32_t), &value, sizeof(uint32_t)); + vRequests.push_back(request); + } + + return pKmdSysManager->requestMultiple(vRequests, vResponses); +} + +ze_result_t WddmFanImp::getState(zes_fan_speed_units_t units, int32_t *pSpeed) { + if (units == ZES_FAN_SPEED_UNITS_PERCENT) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + + KmdSysman::RequestProperty request; + KmdSysman::ResponseProperty response; + + request.commandId = KmdSysman::Command::Get; + request.componentId = KmdSysman::Component::FanComponent; + request.requestId = KmdSysman::Requests::Fans::CurrentFanSpeed; + + ze_result_t status = pKmdSysManager->requestSingle(request, response); + + if (status != ZE_RESULT_SUCCESS) { + return status; + } + + uint32_t value = 0; + memcpy_s(&value, sizeof(uint32_t), response.dataBuffer, sizeof(uint32_t)); + + *pSpeed = static_cast(value); + + return status; +} + +bool WddmFanImp::isFanModuleSupported() { + KmdSysman::RequestProperty request = {}; + KmdSysman::ResponseProperty response = {}; + + request.commandId = KmdSysman::Command::Get; + request.componentId = KmdSysman::Component::FanComponent; + request.requestId = KmdSysman::Requests::Fans::CurrentFanSpeed; + + return (pKmdSysManager->requestSingle(request, response) == ZE_RESULT_SUCCESS); +} + +WddmFanImp::WddmFanImp(OsSysman *pOsSysman) { + WddmSysmanImp *pWddmSysmanImp = static_cast(pOsSysman); + pKmdSysManager = &pWddmSysmanImp->getKmdSysManager(); +} + +std::unique_ptr OsFan::create(OsSysman *pOsSysman) { + std::unique_ptr pWddmFanImp = std::make_unique(pOsSysman); + return pWddmFanImp; +} + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/fan/windows/sysman_os_fan_imp.h b/level_zero/sysman/source/fan/windows/sysman_os_fan_imp.h new file mode 100644 index 0000000000..bb42abe1d8 --- /dev/null +++ b/level_zero/sysman/source/fan/windows/sysman_os_fan_imp.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "shared/source/helpers/non_copyable_or_moveable.h" + +#include "level_zero/sysman/source/fan/sysman_os_fan.h" +#include "level_zero/sysman/source/windows/zes_os_sysman_imp.h" + +namespace L0 { +namespace Sysman { + +class KmdSysManager; +class WddmFanImp : public OsFan, NEO::NonCopyableOrMovableClass { + public: + ze_result_t getProperties(zes_fan_properties_t *pProperties) override; + ze_result_t getConfig(zes_fan_config_t *pConfig) override; + ze_result_t setDefaultMode() override; + ze_result_t setFixedSpeedMode(const zes_fan_speed_t *pSpeed) override; + ze_result_t setSpeedTableMode(const zes_fan_speed_table_t *pSpeedTable) override; + ze_result_t getState(zes_fan_speed_units_t units, int32_t *pSpeed) override; + bool isFanModuleSupported() override; + + WddmFanImp(OsSysman *pOsSysman); + WddmFanImp() = default; + ~WddmFanImp() override = default; + + protected: + KmdSysManager *pKmdSysManager = nullptr; + + private: + uint64_t prevTS = 0; + uint32_t prevPulses = 0; + int32_t maxPoints = 0; +}; + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/sysman_device.cpp b/level_zero/sysman/source/sysman_device.cpp index d31f78eeb3..e269f5fbe4 100644 --- a/level_zero/sysman/source/sysman_device.cpp +++ b/level_zero/sysman/source/sysman_device.cpp @@ -149,5 +149,10 @@ ze_result_t SysmanDevice::pciGetStats(zes_device_handle_t hDevice, zes_pci_stats return pSysmanDevice->pciGetStats(pStats); } +ze_result_t SysmanDevice::fanGet(zes_device_handle_t hDevice, uint32_t *pCount, zes_fan_handle_t *phFan) { + auto pSysmanDevice = L0::Sysman::SysmanDevice::fromHandle(hDevice); + return pSysmanDevice->fanGet(pCount, phFan); +} + } // namespace Sysman } // namespace L0 diff --git a/level_zero/sysman/source/sysman_device.h b/level_zero/sysman/source/sysman_device.h index d037ffbb13..ee8736b6ad 100644 --- a/level_zero/sysman/source/sysman_device.h +++ b/level_zero/sysman/source/sysman_device.h @@ -13,6 +13,7 @@ #include "level_zero/sysman/source/ecc/sysman_ecc.h" #include "level_zero/sysman/source/engine/sysman_engine.h" #include "level_zero/sysman/source/fabric_port/sysman_fabric_port.h" +#include "level_zero/sysman/source/fan/sysman_fan.h" #include "level_zero/sysman/source/firmware/sysman_firmware.h" #include "level_zero/sysman/source/frequency/sysman_frequency.h" #include "level_zero/sysman/source/global_operations/sysman_global_operations.h" @@ -111,6 +112,8 @@ struct SysmanDevice : _ze_device_handle_t { static ze_result_t pciGetStats(zes_device_handle_t hDevice, zes_pci_stats_t *pStats); virtual ze_result_t pciGetStats(zes_pci_stats_t *pStats) = 0; + static ze_result_t fanGet(zes_device_handle_t hDevice, uint32_t *pCount, zes_fan_handle_t *phFan); + virtual ze_result_t fanGet(uint32_t *pCount, zes_fan_handle_t *phFan) = 0; }; } // namespace Sysman diff --git a/level_zero/sysman/source/sysman_device_imp.cpp b/level_zero/sysman/source/sysman_device_imp.cpp index 44043a1e05..350b006ae3 100644 --- a/level_zero/sysman/source/sysman_device_imp.cpp +++ b/level_zero/sysman/source/sysman_device_imp.cpp @@ -10,6 +10,7 @@ #include "shared/source/helpers/debug_helpers.h" #include "level_zero/sysman/source/ecc/sysman_ecc_imp.h" +#include "level_zero/sysman/source/fan/sysman_fan_imp.h" #include "level_zero/sysman/source/global_operations/sysman_global_operations_imp.h" #include "level_zero/sysman/source/os_sysman.h" #include "level_zero/sysman/source/pci/sysman_pci_imp.h" @@ -39,6 +40,7 @@ SysmanDeviceImp::SysmanDeviceImp(NEO::ExecutionEnvironment *executionEnvironment pEcc = new EccImp(pOsSysman); pTempHandleContext = new TemperatureHandleContext(pOsSysman); pPci = new PciImp(pOsSysman); + pFanHandleContext = new FanHandleContext(pOsSysman); } SysmanDeviceImp::~SysmanDeviceImp() { @@ -57,6 +59,7 @@ SysmanDeviceImp::~SysmanDeviceImp() { freeResource(pEcc); freeResource(pTempHandleContext); freeResource(pPci); + freeResource(pFanHandleContext); freeResource(pOsSysman); executionEnvironment->decRefInternal(); } @@ -169,5 +172,9 @@ ze_result_t SysmanDeviceImp::pciGetStats(zes_pci_stats_t *pStats) { return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; } +ze_result_t SysmanDeviceImp::fanGet(uint32_t *pCount, zes_fan_handle_t *phFan) { + return pFanHandleContext->fanGet(pCount, phFan); +} + } // namespace Sysman } // namespace L0 diff --git a/level_zero/sysman/source/sysman_device_imp.h b/level_zero/sysman/source/sysman_device_imp.h index 1e793a3809..5aace8647b 100644 --- a/level_zero/sysman/source/sysman_device_imp.h +++ b/level_zero/sysman/source/sysman_device_imp.h @@ -52,6 +52,7 @@ struct SysmanDeviceImp : SysmanDevice, NEO::NonCopyableOrMovableClass { Ecc *pEcc = nullptr; TemperatureHandleContext *pTempHandleContext = nullptr; Pci *pPci = nullptr; + FanHandleContext *pFanHandleContext = nullptr; ze_result_t powerGet(uint32_t *pCount, zes_pwr_handle_t *phPower) override; ze_result_t powerGetCardDomain(zes_pwr_handle_t *phPower) override; @@ -78,6 +79,7 @@ struct SysmanDeviceImp : SysmanDevice, NEO::NonCopyableOrMovableClass { ze_result_t pciGetState(zes_pci_state_t *pState) override; ze_result_t pciGetBars(uint32_t *pCount, zes_pci_bar_properties_t *pProperties) override; ze_result_t pciGetStats(zes_pci_stats_t *pStats) override; + ze_result_t fanGet(uint32_t *pCount, zes_fan_handle_t *phFan) override; private: NEO::ExecutionEnvironment *executionEnvironment = nullptr; diff --git a/level_zero/sysman/test/unit_tests/sources/fan/CMakeLists.txt b/level_zero/sysman/test/unit_tests/sources/fan/CMakeLists.txt new file mode 100644 index 0000000000..afbd6f0832 --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/fan/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (C) 2023 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +target_sources(${TARGET_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt +) + +add_subdirectories() diff --git a/level_zero/sysman/test/unit_tests/sources/fan/linux/CMakeLists.txt b/level_zero/sysman/test/unit_tests/sources/fan/linux/CMakeLists.txt new file mode 100644 index 0000000000..cbcbd355a1 --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/fan/linux/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright (C) 2023 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +if(UNIX) + target_sources(${TARGET_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/test_zes_fan.cpp + ) +endif() diff --git a/level_zero/sysman/test/unit_tests/sources/fan/linux/test_zes_fan.cpp b/level_zero/sysman/test/unit_tests/sources/fan/linux/test_zes_fan.cpp new file mode 100644 index 0000000000..8dff1c8b8b --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/fan/linux/test_zes_fan.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/source/fan/linux/sysman_os_fan_imp.h" +#include "level_zero/sysman/source/fan/sysman_fan_imp.h" +#include "level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_fixture.h" + +namespace L0 { +namespace ult { + +constexpr uint32_t fanHandleComponentCount = 0u; +class SysmanDeviceFanFixture : public SysmanDeviceFixture { + protected: + std::unique_ptr pFan; + L0::Sysman::SysmanDevice *device = nullptr; + + void SetUp() override { + SysmanDeviceFixture::SetUp(); + device = pSysmanDevice; + pFan = std::make_unique(pOsSysman); + } + + void TearDown() override { + SysmanDeviceFixture::TearDown(); + } + + std::vector getFanHandles(uint32_t count) { + std::vector handles(count, nullptr); + EXPECT_EQ(zesDeviceEnumFans(device->toHandle(), &count, handles.data()), ZE_RESULT_SUCCESS); + return handles; + } +}; + +TEST_F(SysmanDeviceFanFixture, GivenComponentCountZeroWhenEnumeratingFanDomainsThenValidCountIsReturnedAndVerifySysmanFanGetCallSucceeds) { + uint32_t count = 0; + EXPECT_EQ(zesDeviceEnumFans(device->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, fanHandleComponentCount); +} + +TEST_F(SysmanDeviceFanFixture, GivenInvalidComponentCountWhenEnumeratingFanDomainsThenValidCountIsReturnedAndVerifySysmanFanGetCallSucceeds) { + uint32_t count = 0; + EXPECT_EQ(zesDeviceEnumFans(device->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, fanHandleComponentCount); + + count = count + 1; + EXPECT_EQ(zesDeviceEnumFans(device->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, fanHandleComponentCount); +} + +TEST_F(SysmanDeviceFanFixture, GivenComponentCountZeroWhenEnumeratingFanDomainsThenValidFanHandlesIsReturned) { + uint32_t count = 0; + EXPECT_EQ(zesDeviceEnumFans(device->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, fanHandleComponentCount); + + std::vector handles(count, nullptr); + EXPECT_EQ(zesDeviceEnumFans(device->toHandle(), &count, handles.data()), ZE_RESULT_SUCCESS); + for (auto handle : handles) { + EXPECT_NE(handle, nullptr); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanPropertiesThenCallSucceeds) { + zes_fan_handle_t fanHandle = pFan->toHandle(); + zes_fan_properties_t properties; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesFanGetProperties(fanHandle, &properties)); +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanConfigThenUnsupportedIsReturned) { + zes_fan_handle_t fanHandle = pFan->toHandle(); + zes_fan_config_t fanConfig; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesFanGetConfig(fanHandle, &fanConfig)); +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenSettingDefaultModeThenUnsupportedIsReturned) { + zes_fan_handle_t fanHandle = pFan->toHandle(); + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesFanSetDefaultMode(fanHandle)); +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenSettingFixedSpeedModeThenUnsupportedIsReturned) { + zes_fan_handle_t fanHandle = pFan->toHandle(); + zes_fan_speed_t fanSpeed = {0}; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesFanSetFixedSpeedMode(fanHandle, &fanSpeed)); +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenSettingTheSpeedTableModeThenUnsupportedIsReturned) { + zes_fan_handle_t fanHandle = pFan->toHandle(); + zes_fan_speed_table_t fanSpeedTable = {0}; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesFanSetSpeedTableMode(fanHandle, &fanSpeedTable)); +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanSpeedWithRPMUnitThenValidFanSpeedReadingsRetrieved) { + zes_fan_handle_t fanHandle = pFan->toHandle(); + zes_fan_speed_units_t unit = zes_fan_speed_units_t::ZES_FAN_SPEED_UNITS_RPM; + int32_t fanSpeed = 0; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesFanGetState(fanHandle, unit, &fanSpeed)); +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanSpeedWithPercentUnitThenUnsupportedIsReturned) { + zes_fan_handle_t fanHandle = pFan->toHandle(); + zes_fan_speed_units_t unit = zes_fan_speed_units_t::ZES_FAN_SPEED_UNITS_PERCENT; + int32_t fanSpeed = 0; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesFanGetState(fanHandle, unit, &fanSpeed)); +} + +} // namespace ult +} // namespace L0 diff --git a/level_zero/sysman/test/unit_tests/sources/fan/windows/CMakeLists.txt b/level_zero/sysman/test/unit_tests/sources/fan/windows/CMakeLists.txt new file mode 100644 index 0000000000..09d7c430f4 --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/fan/windows/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# Copyright (C) 2023 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +if(WIN32) + target_sources(${TARGET_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/test_zes_sysman_fan.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mock_fan.h + ) +endif() diff --git a/level_zero/sysman/test/unit_tests/sources/fan/windows/mock_fan.h b/level_zero/sysman/test/unit_tests/sources/fan/windows/mock_fan.h new file mode 100644 index 0000000000..31afcc0e00 --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/fan/windows/mock_fan.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "level_zero/sysman/source/fan/sysman_fan_imp.h" +#include "level_zero/sysman/test/unit_tests/sources/windows/mock_kmd_sys_manager.h" + +namespace L0 { +namespace ult { + +struct MockFanKmdSysManager : public MockKmdSysManager { + union { + struct + { + uint32_t TemperatureDegreesCelsius : 16; + uint32_t FanSpeedPercent : 16; + }; + uint32_t Data; + } mockFanTempSpeed; + uint32_t mockFanMaxPoints = 10; + uint32_t mockFanCurrentPulses = 523436; + uint32_t mockFanCurrentFanPoints = 0; + + void getFanProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) override { + uint8_t *pBuffer = reinterpret_cast(pResponse); + pBuffer += sizeof(KmdSysman::GfxSysmanReqHeaderOut); + + switch (pRequest->inRequestId) { + case KmdSysman::Requests::Fans::MaxFanControlPointsSupported: { + uint32_t *pValue = reinterpret_cast(pBuffer); + *pValue = mockFanMaxPoints; + pResponse->outReturnCode = KmdSysman::KmdSysmanSuccess; + pResponse->outDataSize = sizeof(uint32_t); + } break; + case KmdSysman::Requests::Fans::CurrentFanSpeed: { + if (fanSupported) { + uint32_t *pValue = reinterpret_cast(pBuffer); + *pValue = mockFanCurrentPulses; + pResponse->outReturnCode = KmdSysman::KmdSysmanSuccess; + pResponse->outDataSize = sizeof(uint32_t); + } else { + pResponse->outDataSize = 0; + pResponse->outReturnCode = KmdSysman::KmdSysmanFail; + } + } break; + case KmdSysman::Requests::Fans::CurrentNumOfControlPoints: { + uint32_t *pValue = reinterpret_cast(pBuffer); + *pValue = mockFanCurrentFanPoints; + pResponse->outReturnCode = KmdSysman::KmdSysmanSuccess; + pResponse->outDataSize = sizeof(uint32_t); + } break; + case KmdSysman::Requests::Fans::CurrentFanPoint: { + uint32_t *pValue = reinterpret_cast(pBuffer); + mockFanTempSpeed.FanSpeedPercent = 25; + mockFanTempSpeed.TemperatureDegreesCelsius = 50; + *pValue = mockFanTempSpeed.Data; + pResponse->outReturnCode = KmdSysman::KmdSysmanSuccess; + pResponse->outDataSize = sizeof(uint32_t); + } break; + default: { + pResponse->outDataSize = 0; + pResponse->outReturnCode = KmdSysman::KmdSysmanFail; + } break; + } + } + + void setFanProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) override { + uint8_t *pBuffer = reinterpret_cast(pRequest); + pBuffer += sizeof(KmdSysman::GfxSysmanReqHeaderIn); + + switch (pRequest->inRequestId) { + case KmdSysman::Requests::Fans::CurrentNumOfControlPoints: { + uint32_t *pValue = reinterpret_cast(pBuffer); + mockFanCurrentFanPoints = *pValue; + pResponse->outDataSize = 0; + if ((mockFanCurrentFanPoints % 2 == 0) && (mockFanCurrentFanPoints > 0) && (mockFanCurrentFanPoints <= mockFanMaxPoints)) { + pResponse->outReturnCode = KmdSysman::KmdSysmanSuccess; + } else if (mockFanCurrentFanPoints == 0) { + pResponse->outReturnCode = KmdSysman::KmdSysmanSuccess; + } else { + pResponse->outReturnCode = KmdSysman::KmdSysmanFail; + } + } break; + case KmdSysman::Requests::Fans::CurrentFanPoint: { + uint32_t *pValue = reinterpret_cast(pBuffer); + mockFanTempSpeed.Data = *pValue; + pResponse->outDataSize = 0; + pResponse->outReturnCode = KmdSysman::KmdSysmanSuccess; + } break; + default: { + pResponse->outDataSize = 0; + pResponse->outReturnCode = KmdSysman::KmdSysmanFail; + } break; + } + } +}; + +} // namespace ult +} // namespace L0 diff --git a/level_zero/sysman/test/unit_tests/sources/fan/windows/test_zes_sysman_fan.cpp b/level_zero/sysman/test/unit_tests/sources/fan/windows/test_zes_sysman_fan.cpp new file mode 100644 index 0000000000..d3b2746266 --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/fan/windows/test_zes_sysman_fan.cpp @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/source/fan/windows/sysman_os_fan_imp.h" +#include "level_zero/sysman/test/unit_tests/sources/fan/windows/mock_fan.h" +#include "level_zero/sysman/test/unit_tests/sources/windows/mock_sysman_fixture.h" + +namespace L0 { +namespace ult { + +constexpr uint32_t fanHandleComponentCount = 1u; +class SysmanDeviceFanFixture : public SysmanDeviceFixture { + + protected: + std::unique_ptr pKmdSysManager; + L0::Sysman::KmdSysManager *pOriginalKmdSysManager = nullptr; + void SetUp() override { + SysmanDeviceFixture::SetUp(); + } + + void init(bool allowSetCalls, bool fanSupported) { + pKmdSysManager.reset(new MockFanKmdSysManager); + + pKmdSysManager->allowSetCalls = allowSetCalls; + pKmdSysManager->fanSupported = fanSupported; + + pOriginalKmdSysManager = pWddmSysmanImp->pKmdSysManager; + pWddmSysmanImp->pKmdSysManager = pKmdSysManager.get(); + + pSysmanDeviceImp->pFanHandleContext->handleList.clear(); + } + void TearDown() override { + pWddmSysmanImp->pKmdSysManager = pOriginalKmdSysManager; + SysmanDeviceFixture::TearDown(); + } + + std::vector getFanHandles() { + uint32_t count = 0; + EXPECT_EQ(zesDeviceEnumFans(pSysmanDevice->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + std::vector handles(count, nullptr); + EXPECT_EQ(zesDeviceEnumFans(pSysmanDevice->toHandle(), &count, handles.data()), ZE_RESULT_SUCCESS); + return handles; + } +}; + +TEST_F(SysmanDeviceFanFixture, GivenComponentCountZeroWhenEnumeratingFansThenValidCountIsReturnedAndVerifySysmanPowerGetCallSucceeds) { + init(true, true); + + uint32_t count = 0; + EXPECT_EQ(zesDeviceEnumFans(pSysmanDevice->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, fanHandleComponentCount); +} + +TEST_F(SysmanDeviceFanFixture, GivenInvalidComponentCountWhenEnumeratingFansThenValidCountIsReturnedAndVerifySysmanPowerGetCallSucceeds) { + init(true, true); + + uint32_t count = 0; + EXPECT_EQ(zesDeviceEnumFans(pSysmanDevice->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, fanHandleComponentCount); + + count = count + 1; + EXPECT_EQ(zesDeviceEnumFans(pSysmanDevice->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, fanHandleComponentCount); +} + +TEST_F(SysmanDeviceFanFixture, GivenComponentCountZeroWhenEnumeratingFansThenValidFanHandlesIsReturned) { + init(true, true); + + uint32_t count = 0; + EXPECT_EQ(zesDeviceEnumFans(pSysmanDevice->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, fanHandleComponentCount); + + std::vector handles(count, nullptr); + EXPECT_EQ(zesDeviceEnumFans(pSysmanDevice->toHandle(), &count, handles.data()), ZE_RESULT_SUCCESS); + for (auto handle : handles) { + EXPECT_NE(handle, nullptr); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanPropertiesAllowSetToTrueThenCallSucceeds) { + // Setting allow set calls or not + init(true, true); + + auto handles = getFanHandles(); + + for (auto handle : handles) { + zes_fan_properties_t properties; + + ze_result_t result = zesFanGetProperties(handle, &properties); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_FALSE(properties.onSubdevice); + EXPECT_EQ(properties.subdeviceId, 0); + EXPECT_TRUE(properties.canControl); + EXPECT_EQ(properties.maxPoints, pKmdSysManager->mockFanMaxPoints); + EXPECT_EQ(properties.maxRPM, -1); + EXPECT_EQ(properties.supportedModes, zes_fan_speed_mode_t::ZES_FAN_SPEED_MODE_TABLE); + EXPECT_EQ(properties.supportedUnits, zes_fan_speed_units_t::ZES_FAN_SPEED_UNITS_PERCENT); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanPropertiesAllowSetToFalseThenControlToFalse) { + // Setting allow set calls or not + init(false, true); + + auto handles = getFanHandles(); + + for (auto handle : handles) { + zes_fan_properties_t properties = {}; + ze_result_t result = zesFanGetProperties(handle, &properties); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_FALSE(properties.canControl); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidNoSupportForFanCheckFanHandleCountIsZero) { + // Setting allow set calls or not + init(false, false); + + uint32_t count = 0; + EXPECT_EQ(zesDeviceEnumFans(pSysmanDevice->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, 0u); +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanPropertiesAllowSetToFalseThenCallSucceeds) { + // Setting allow set calls or not + init(true, true); + + auto handles = getFanHandles(); + + for (auto handle : handles) { + zes_fan_properties_t properties; + + ze_result_t result = zesFanGetProperties(handle, &properties); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_FALSE(properties.onSubdevice); + EXPECT_EQ(properties.subdeviceId, 0); + EXPECT_TRUE(properties.canControl); + EXPECT_EQ(properties.maxPoints, pKmdSysManager->mockFanMaxPoints); + EXPECT_EQ(properties.maxRPM, -1); + EXPECT_EQ(properties.supportedModes, zes_fan_speed_mode_t::ZES_FAN_SPEED_MODE_TABLE); + EXPECT_EQ(properties.supportedUnits, zes_fan_speed_units_t::ZES_FAN_SPEED_UNITS_PERCENT); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanConfigThenSuccessIsReturnedDefaultFanTable) { + // Setting allow set calls or not + init(true, true); + + auto handles = getFanHandles(); + + for (auto handle : handles) { + zes_fan_config_t fanConfig; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesFanSetDefaultMode(handle)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zesFanGetConfig(handle, &fanConfig)); + EXPECT_EQ(fanConfig.mode, ZES_FAN_SPEED_MODE_DEFAULT); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanConfigThenFirstSingleRequestFails) { + // Setting allow set calls or not + init(true, true); + + auto handles = getFanHandles(); + + pKmdSysManager->mockRequestSingle = TRUE; + pKmdSysManager->mockRequestSingleResult = ZE_RESULT_ERROR_NOT_AVAILABLE; + + for (auto handle : handles) { + zes_fan_config_t fanConfig; + EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, zesFanGetConfig(handle, &fanConfig)); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanConfigWithValidFanPointsSuccessCustomFanTable) { + // Setting allow set calls or not + init(true, true); + + auto handles = getFanHandles(); + + for (auto handle : handles) { + zes_fan_speed_table_t fanSpeedTable = {0}; + fanSpeedTable.numPoints = 4; + fanSpeedTable.table[0].speed.speed = 65; + fanSpeedTable.table[0].speed.units = ZES_FAN_SPEED_UNITS_PERCENT; + fanSpeedTable.table[0].temperature = 30; + + fanSpeedTable.table[1].speed.speed = 75; + fanSpeedTable.table[1].speed.units = ZES_FAN_SPEED_UNITS_PERCENT; + fanSpeedTable.table[1].temperature = 45; + + fanSpeedTable.table[2].speed.speed = 85; + fanSpeedTable.table[2].speed.units = ZES_FAN_SPEED_UNITS_PERCENT; + fanSpeedTable.table[2].temperature = 60; + + fanSpeedTable.table[3].speed.speed = 100; + fanSpeedTable.table[3].speed.units = ZES_FAN_SPEED_UNITS_PERCENT; + fanSpeedTable.table[3].temperature = 90; + + EXPECT_EQ(ZE_RESULT_SUCCESS, zesFanSetSpeedTableMode(handle, &fanSpeedTable)); + + zes_fan_config_t fanConfig; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesFanGetConfig(handle, &fanConfig)); + EXPECT_EQ(fanConfig.mode, ZES_FAN_SPEED_MODE_TABLE); + EXPECT_EQ(fanConfig.speedTable.numPoints, 4); + EXPECT_EQ(fanConfig.speedTable.table[0].speed.units, ZES_FAN_SPEED_UNITS_PERCENT); + EXPECT_EQ(fanConfig.speedTable.table[1].speed.units, ZES_FAN_SPEED_UNITS_PERCENT); + EXPECT_EQ(fanConfig.speedTable.table[2].speed.units, ZES_FAN_SPEED_UNITS_PERCENT); + EXPECT_EQ(fanConfig.speedTable.table[3].speed.units, ZES_FAN_SPEED_UNITS_PERCENT); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenSettingDefaultModeThenSupportedIsReturned) { + // Setting allow set calls or not + init(true, true); + + auto handles = getFanHandles(); + + for (auto handle : handles) { + EXPECT_EQ(ZE_RESULT_SUCCESS, zesFanSetDefaultMode(handle)); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenSettingFixedSpeedModeThenUnsupportedIsReturned) { + // Setting allow set calls or not + init(true, true); + + auto handles = getFanHandles(); + + for (auto handle : handles) { + zes_fan_speed_t fanSpeed = {0}; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesFanSetFixedSpeedMode(handle, &fanSpeed)); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenSettingTheSpeedTableModeWithNumberOfPointsZeroThenUnsupportedIsReturned) { + // Setting allow set calls or not + init(true, true); + + auto handles = getFanHandles(); + + for (auto handle : handles) { + zes_fan_speed_table_t fanSpeedTable = {0}; + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, zesFanSetSpeedTableMode(handle, &fanSpeedTable)); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenSettingTheSpeedTableModeWithGreaterThanMaxNumberOfPointsThenUnsupportedIsReturned) { + // Setting allow set calls or not + init(true, true); + + auto handles = getFanHandles(); + + for (auto handle : handles) { + zes_fan_speed_table_t fanSpeedTable = {0}; + fanSpeedTable.numPoints = 20; // Setting number of control points greater than max number of control points (10) + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, zesFanSetSpeedTableMode(handle, &fanSpeedTable)); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanSpeedWithRPMUnitThenValidFanSpeedReadingsRetrieved) { + // Setting allow set calls or not + init(true, true); + + auto handles = getFanHandles(); + + for (auto handle : handles) { + zes_fan_speed_units_t unit = zes_fan_speed_units_t::ZES_FAN_SPEED_UNITS_RPM; + int32_t fanSpeed = 0; + ze_result_t result = zesFanGetState(handle, unit, &fanSpeed); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_GT(fanSpeed, 0); + } +} + +TEST_F(SysmanDeviceFanFixture, GivenValidFanHandleWhenGettingFanSpeedWithPercentUnitThenUnsupportedIsReturned) { + // Setting allow set calls or not + init(true, true); + + auto handles = getFanHandles(); + + for (auto handle : handles) { + zes_fan_speed_units_t unit = zes_fan_speed_units_t::ZES_FAN_SPEED_UNITS_PERCENT; + int32_t fanSpeed = 0; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesFanGetState(handle, unit, &fanSpeed)); + } +} + +} // namespace ult +} // namespace L0 diff --git a/level_zero/tools/source/sysman/fan/fan.h b/level_zero/tools/source/sysman/fan/fan.h index f3b7e844ed..b5b4bae569 100644 --- a/level_zero/tools/source/sysman/fan/fan.h +++ b/level_zero/tools/source/sysman/fan/fan.h @@ -6,16 +6,13 @@ */ #pragma once +#include "level_zero/api/sysman/zes_handles_struct.h" #include #include #include #include -struct _zes_fan_handle_t { - virtual ~_zes_fan_handle_t() = default; -}; - namespace L0 { struct OsSysman; diff --git a/level_zero/tools/test/black_box_tests/zello_sysman.cpp b/level_zero/tools/test/black_box_tests/zello_sysman.cpp index e119c9f731..f9be97d700 100644 --- a/level_zero/tools/test/black_box_tests/zello_sysman.cpp +++ b/level_zero/tools/test/black_box_tests/zello_sysman.cpp @@ -126,6 +126,7 @@ void usage() { "\n -P, --performance selectively run performance black box test" "\n [--setconfig ] optionally set the performance factor for the particular handle" "\n -C, --ecc selectively run ecc black box test" + "\n -a, --fan selectively run fan black box test" "\n -h, --help display help message" "\n" "\n All L0 Syman APIs that set values require root privileged execution" @@ -1327,17 +1328,86 @@ void testSysmanDiagnostics(ze_device_handle_t &device) { } } +std::string getFanModes(uint32_t fanMode) { + static const std::map mgetFanMode{ + {0, "ZES_FAN_SPEED_MODE_DEFAULT"}, + {1, "ZES_FAN_SPEED_MODE_FIXED"}, + {2, "ZES_FAN_SPEED_MODE_TABLE"}}; + auto i = mgetFanMode.find(fanMode); + if (i == mgetFanMode.end()) + return "NOT SUPPORTED FAN MODE SET"; + else + return mgetFanMode.at(fanMode); +} + +std::string getFanUnits(uint32_t fanUnit) { + static const std::map mgetFanUnit{ + {0, "ZES_FAN_SPEED_UNITS_RPM"}, + {1, "ZES_FAN_SPEED_UNITS_PERCENT"}}; + auto i = mgetFanUnit.find(fanUnit); + if (i == mgetFanUnit.end()) + return "NOT SUPPORTED FAN UNIT SET"; + else + return mgetFanUnit.at(fanUnit); +} + +void testSysmanFan(ze_device_handle_t &device) { + std::cout << std::endl + << " ---- Fan tests ---- " << std::endl; + uint32_t count = 0; + VALIDATECALL(zesDeviceEnumFans(device, &count, nullptr)); + if (count == 0) { + std::cout << "Could not retrieve Fans" << std::endl; + return; + } + std::vector handles(count, nullptr); + VALIDATECALL(zesDeviceEnumFans(device, &count, handles.data())); + + for (auto handle : handles) { + zes_fan_properties_t fanProperties = {}; + zes_fan_config_t fanConfig = {}; + zes_fan_speed_units_t fanUnit = {}; + int32_t fanSpeed; + + VALIDATECALL(zesFanGetProperties(handle, &fanProperties)); + if (verbose) { + std::cout << "On Subdevice = " << static_cast(fanProperties.onSubdevice) << std::endl; + std::cout << "Subdevice Id = " << fanProperties.subdeviceId << std::endl; + std::cout << "Can control = " << static_cast(fanProperties.canControl) << std::endl; + std::cout << "Supported modes = " << getFanModes(fanProperties.supportedModes) << std::endl; + std::cout << "Supported units = " << getFanUnits(fanProperties.supportedUnits) << std::endl; + std::cout << "Max RPM = " << fanProperties.maxRPM << std::endl; + std::cout << "MAX Points = " << fanProperties.maxPoints << std::endl; + } + + VALIDATECALL(zesFanGetConfig(handle, &fanConfig)); + if (verbose) { + std::cout << std::endl + << " ---- Fan get config tests ---- " << std::endl; + std::cout << "Mode = " << getFanModes(fanConfig.mode) << std::endl; + std::cout << "Fan Speed = " << fanConfig.speedFixed.speed << std::endl; + std::cout << "Fan Speed Unit = " << getFanUnits(fanConfig.speedFixed.units) << std::endl; + } + + VALIDATECALL(zesFanGetState(handle, fanUnit, &fanSpeed)); + if (verbose) { + std::cout << std::endl + << " ---- Fan get State tests ---- " << std::endl; + std::cout << "Fan Speed = " << fanSpeed << std::endl; + std::cout << "Fan Speed Unit = " << getFanUnits(fanUnit) << std::endl; + } + } +} + bool checkpFactorArguments(std::vector &devices, std::vector &buf) { uint32_t deviceIndex = static_cast(std::stoi(buf[1])); if (deviceIndex >= devices.size()) { return false; } - uint32_t subDeviceCount = 0; zes_device_properties_t properties = {}; VALIDATECALL(zesDeviceGetProperties(devices[deviceIndex], &properties)); subDeviceCount = properties.numSubdevices; - uint32_t subDeviceIndex = static_cast(std::stoi(buf[2])); if (subDeviceCount > 0 && subDeviceIndex >= subDeviceCount) { return false; @@ -1592,6 +1662,11 @@ int main(int argc, char *argv[]) { testSysmanDiagnostics(device); }); } + if (isParamEnabled(argc, argv, "-a", "--fan", &optind)) { + std::for_each(devices.begin(), devices.end(), [&](auto device) { + testSysmanFan(device); + }); + } return 0; }