From 8733e9ab950b48a45774d8411f12f792b097bde8 Mon Sep 17 00:00:00 2001 From: Girish Pathak Date: Mon, 24 Feb 2025 11:10:36 +0000 Subject: [PATCH] module/scmi_telemetry: Introduce new SCMI Telemetry module Add a new SCMI Telemetry module to support telemetry management via the i SCMI protocol. This includes handling telemetry data events, shared memory interfaces, and configuration mechanisms as per the SCMI specification. Note: This is not a complete implementation on of the SCMI telemetry protocol as specified by the SCMI specification but the introduced module should provide basic implementation that will in future allow additional features. The complete SCMI protocol implementation will have three modules 1. module/scmi_telemetry, which implements SCMI telemetry protocol 2. module/telemetry, The core logic of telemetry protocol 3. Example telemetry source driver, This will demonsrate actual telemetry data sharing with the agent As next steps, future commits will provide implementation of above along with example configuration and unit tests. Change-Id: I0dd1cff483fe2da388fbb5bde8269c411d018786 Signed-off-by: Girish Pathak --- module/scmi_telemetry/CMakeLists.txt | 23 + module/scmi_telemetry/Module.cmake | 9 + .../include/internal/scmi_telemetry.h | 668 +++++++ .../include/mod_scmi_telemetry.h | 145 ++ .../scmi_telemetry/src/mod_scmi_telemetry.c | 1548 +++++++++++++++++ 5 files changed, 2393 insertions(+) create mode 100644 module/scmi_telemetry/CMakeLists.txt create mode 100644 module/scmi_telemetry/Module.cmake create mode 100644 module/scmi_telemetry/include/internal/scmi_telemetry.h create mode 100644 module/scmi_telemetry/include/mod_scmi_telemetry.h create mode 100644 module/scmi_telemetry/src/mod_scmi_telemetry.c diff --git a/module/scmi_telemetry/CMakeLists.txt b/module/scmi_telemetry/CMakeLists.txt new file mode 100644 index 000000000..c43bcf5b9 --- /dev/null +++ b/module/scmi_telemetry/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +add_library(${SCP_MODULE_TARGET} SCP_MODULE) + +target_include_directories(${SCP_MODULE_TARGET} + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") + +target_sources( + ${SCP_MODULE_TARGET} + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/mod_scmi_telemetry.c") + +target_link_libraries(${SCP_MODULE_TARGET} PRIVATE module-telemetry) + +target_link_libraries(${SCP_MODULE_TARGET} PRIVATE module-scmi) + +if("resource-perms" IN_LIST SCP_MODULES) + target_link_libraries(${SCP_MODULE_TARGET} PRIVATE module-resource-perms) +endif() diff --git a/module/scmi_telemetry/Module.cmake b/module/scmi_telemetry/Module.cmake new file mode 100644 index 000000000..b9f474c8b --- /dev/null +++ b/module/scmi_telemetry/Module.cmake @@ -0,0 +1,9 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +set(SCP_MODULE "scmi-telemetry") +set(SCP_MODULE_TARGET "module-scmi-telemetry") diff --git a/module/scmi_telemetry/include/internal/scmi_telemetry.h b/module/scmi_telemetry/include/internal/scmi_telemetry.h new file mode 100644 index 000000000..d0c62828e --- /dev/null +++ b/module/scmi_telemetry/include/internal/scmi_telemetry.h @@ -0,0 +1,668 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * System Control and Management Interface (SCMI) support for Telemetry + * Management Protocol. + */ + +#ifndef INTERNAL_SCMI_TELEMETRY_H +#define INTERNAL_SCMI_TELEMETRY_H + +#include + +#include + +#include + +/*! + * \addtogroup GroupModules Modules + * \{ + */ + +/*! + * \defgroup GroupSCMI_TELEMETRY SCMI Telemetry Protocol. + * \{ + */ + +#define SCMI_PROTOCOL_VERSION_TELEMETRY UINT32_C(0x10000) + +/* + * NEGOTIATE_PROTOCOL_VERSION + */ +struct scmi_telemetry_negotiate_protocol_version_a2p { + uint32_t version; +}; + +/* + * PROTOCOL_ATTRIBUTES + */ + +/* + * SCMI Telemetry Protocol Attributes Macros + * + * These macros define bit positions and masks for encoding various attributes + * of the SCMI (System Control and Management Interface) Telemetry protocol. + * These attributes help describe the protocol capabilities and behaviors. + */ + +/* Bit position indicating support for asynchronous telemetry read operations */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_POS 31 + +/* Bit position indicating support for continuous telemetry updates */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_POS 30 + +/* Bit position indicating whether telemetry reset is supported */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_POS 17 + +/* Bit position indicating Fast Channel (FCH) support */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_POS 16 + +/* Bit position indicating the number of available Shared Memory Telemetry + * Interfaces (SHMTI) */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_POS 0 + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_MASK + * + * Mask for enabling or disabling asynchronous telemetry reading. + * When set, this indicates that telemetry data can be read asynchronously. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_POS) + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_MASK + * + * Mask for enabling or disabling continuous updates. + * When set, this indicates that telemetry data is updated continuously. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_POS) + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_MASK + * + * Mask to extract or set the number of Shared Memory Telemetry Interfaces + * (SHMTI). This defines how many SHMTI instances are available. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_POS) + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_MASK + * + * Mask indicating whether telemetry reset is supported. + * When set, the protocol supports resetting telemetry data. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_POS) + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_MASK + * + * Mask indicating support for Fast Channel (FCH) + * functionality. This feature allows better frequency coordination across + * multiple components. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_POS) + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTRIBUTES + * + * Macro to encode SCMI Telemetry Protocol attributes into a single 32-bit + * value. This macro shifts and combines various flags and values to form the + * protocol attributes. + * + * Parameters: + * - ASYNC: Enables asynchronous telemetry data reading (1 = enabled, 0 = + * disabled). + * - CONTINUOUS_UPDATE: Enables continuous telemetry updates (1 = enabled, 0 = + * disabled). + * - TELEMETRY_RESET: Indicates whether telemetry reset is supported (1 = + * supported, 0 = not supported). + * - FCH: Enables Fast Channel support (1 = enabled, 0 = + * disabled). + * - NUM_SHMTI: Specifies the number of available SHMTI instances. + * + * Returns: + * - A 32-bit encoded value representing the protocol attributes. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTRIBUTES( \ + ASYNC, CONTINUOUS_UPDATE, TELEMETRY_RESET, FCH, NUM_SHMTI) \ + ( \ + (((ASYNC) << SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_POS) & \ + SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_MASK) | \ + (((CONTINUOUS_UPDATE) \ + << SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_POS) & \ + SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_MASK) | \ + (((TELEMETRY_RESET) \ + << SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_POS) & \ + SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_MASK) | \ + (((FCH) << SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_POS) & \ + SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_MASK) | \ + (((NUM_SHMTI) << SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_POS) & \ + SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_MASK)) +/*! + * \brief SCMI Telemetry Protocol Attributes Response Structure + * + * This structure is used to return protocol attributes when handling + * an SCMI protocol attributes request. + */ +struct scmi_telemetry_protocol_attributes_p2a { + /*! Status of the SCMI request (SCMI_SUCCESS, SCMI_NOT_FOUND, etc.) */ + int32_t status; + + /*! Total number of Data Event (DE) descriptors available */ + uint32_t num_de; + + /*! Encoded attribute flags representing protocol capabilities */ + uint32_t attributes; +}; + +/*! + * \brief SCMI Telemetry List SHMTI (Shared Memory Telemetry Interface) + * + * This section defines macros and structures for handling SHMTI in the SCMI + * Telemetry protocol. The SHMTI region provides shared memory interfaces + * for telemetry data storage. + */ + +/* Bit position for the number of remaining SHMTI instances */ +#define SCMI_TELEMETRY_LIST_SHMTI_NUM_REMAIN_POS 16 + +/* Bit position for the number of SHMTI instances in the response */ +#define SCMI_TELEMETRY_LIST_SHMTI_NUM_POS 0 + +/* Mask for extracting the number of remaining SHMTI instances */ +#define SCMI_TELEMETRY_LIST_SHMTI_NUM_REMAIN_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_LIST_SHMTI_NUM_REMAIN_POS) + +/* Mask for extracting the number of SHMTI instances in the response */ +#define SCMI_TELEMETRY_LIST_SHMTI_NUM_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_LIST_SHMTI_NUM_POS) + +/*! + * \brief Compute the total number of SHMTI instances in the response. + * + * \param[in] REMAIN The number of remaining SHMTI instances. + * \param[in] CURRENT The number of SHMTI instances in the current response. + * + * \return A 32-bit value encoding the total number of SHMTI instances. + */ +#define SCMI_TELEMETRY_LIST_SHMTI_TOTAL_SHMTI(REMAIN, CURRENT) \ + ((((REMAIN) << SCMI_TELEMETRY_LIST_SHMTI_NUM_REMAIN_POS) & \ + SCMI_TELEMETRY_LIST_SHMTI_NUM_REMAIN_MASK) | \ + (((CURRENT) << SCMI_TELEMETRY_LIST_SHMTI_NUM_POS) & \ + SCMI_TELEMETRY_LIST_SHMTI_NUM_MASK)) + +/*! + * \brief SCMI response structure for listing SHMTI instances. + * + * This structure is used in the SCMI Telemetry List SHMTI response, + * containing the number of available SHMTI instances and their descriptors. + */ +struct scmi_telemetry_list_shmti_p2a { + int32_t status; /*!< Status of the SCMI request (SCMI_SUCCESS, etc.) */ + uint32_t num_shmti; /*!< Number of SHMTI instances in the response */ + struct mod_telemetry_shmti_desc + shmti_desc[]; /*!< Array of SHMTI descriptors */ +}; + +/*! + * \brief SCMI Telemetry Data Event (DE) Description + * + * This section defines macros and structures related to telemetry + * data event descriptions in the SCMI protocol. These descriptions + * help configure and retrieve telemetry data. + */ + +/* Bit positions for the number of DE descriptors remaining and current count */ +#define SCMI_TELEMETRY_DE_DESC_NUM_REMAIN_POS 16 +#define SCMI_TELEMETRY_DE_DESC_NUM_POS 0 + +/* Bit masks for extracting DE descriptor counts */ +#define SCMI_TELEMETRY_DE_DESC_NUM_REMAIN_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_DE_DESC_NUM_REMAIN_POS) +#define SCMI_TELEMETRY_DE_DESC_NUM_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_DE_DESC_NUM_POS) + +/*! + * \brief Compute the total number of DE descriptors in the response. + * + * \param[in] REMAIN The number of remaining DE descriptors. + * \param[in] CURRENT The number of DE descriptors in the current response. + * + * \return A 32-bit value encoding the total number of DE descriptors. + */ +#define SCMI_TELEMETRY_DE_DESC_TOTAL(REMAIN, CURRENT) \ + ((((CURRENT) << SCMI_TELEMETRY_DE_DESC_NUM_POS) & \ + SCMI_TELEMETRY_DE_DESC_NUM_MASK) | \ + (((REMAIN) << SCMI_TELEMETRY_DE_DESC_NUM_REMAIN_POS) & \ + SCMI_TELEMETRY_DE_DESC_NUM_REMAIN_MASK)) + +/*! + * \brief Bit positions for DE attribute fields in `de_attributes_1` + */ +#define SCMI_TELEMETRY_DE_FCH_POS 30 +#define SCMI_TELEMETRY_DE_TYPE_POS 22 +#define SCMI_TELEMETRY_DE_PERSISTENT_POS 21 +#define SCMI_TELEMETRY_DE_UNIT_EXP_POS 13 +#define SCMI_TELEMETRY_DE_UNIT_POS 5 +#define SCMI_TELEMETRY_DE_TIMESTAMP_EXP_POS 1 +#define SCMI_TELEMETRY_DE_TIMESTAMP_SUPPORT_POS 0 + +/* Bit masks for `de_attributes_1` */ +#define SCMI_TELEMETRY_DE_FCH_MASK (UINT32_C(0x1) << SCMI_TELEMETRY_DE_FCH_POS) +#define SCMI_TELEMETRY_DE_TYPE_MASK \ + (UINT32_C(0xFF) << SCMI_TELEMETRY_DE_TYPE_POS) +#define SCMI_TELEMETRY_DE_PERSISTENT_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_DE_PERSISTENT_POS) +#define SCMI_TELEMETRY_DE_UNIT_EXP_MASK \ + (UINT32_C(0xFF) << SCMI_TELEMETRY_DE_UNIT_EXP_POS) +#define SCMI_TELEMETRY_DE_UNIT_MASK \ + (UINT32_C(0xFF) << SCMI_TELEMETRY_DE_UNIT_POS) +#define SCMI_TELEMETRY_DE_TIMESTAMP_EXP_MASK \ + (UINT32_C(0xF) << SCMI_TELEMETRY_DE_TIMESTAMP_EXP_POS) +#define SCMI_TELEMETRY_DE_TIMESTAMP_SUPPORT_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_DE_TIMESTAMP_SUPPORT_POS) + +/*! + * \brief Macro to construct `de_attributes_1` field. + * + * \param[in] DE_FCH Fast Channel (1/0) + * \param[in] DE_TYPE Type of Data Event + * \param[in] DE_PERSISTENT Indicates persistent storage (1/0) + * \param[in] DE_UNIT_EXP Exponent value for unit + * \param[in] DE_UNIT Unit identifier + * \param[in] TS_EXP Exponent for timestamp granularity + * \param[in] TS_SUPPORT Timestamp support flag (1/0) + * + * \return Encoded `de_attributes_1` field. + */ +#define SCMI_TELEMETRY_DE_ATTR_1( \ + DE_FCH, DE_TYPE, DE_PERSISTENT, DE_UNIT_EXP, DE_UNIT, TS_EXP, TS_SUPPORT) \ + ((((DE_FCH) << SCMI_TELEMETRY_DE_FCH_POS) & SCMI_TELEMETRY_DE_FCH_MASK) | \ + (((DE_TYPE) << SCMI_TELEMETRY_DE_TYPE_POS) & \ + SCMI_TELEMETRY_DE_TYPE_MASK) | \ + (((DE_PERSISTENT) << SCMI_TELEMETRY_DE_PERSISTENT_POS) & \ + SCMI_TELEMETRY_DE_PERSISTENT_MASK) | \ + (((DE_UNIT_EXP) << SCMI_TELEMETRY_DE_UNIT_EXP_POS) & \ + SCMI_TELEMETRY_DE_UNIT_EXP_MASK) | \ + (((DE_UNIT) << SCMI_TELEMETRY_DE_UNIT_POS) & \ + SCMI_TELEMETRY_DE_UNIT_MASK) | \ + (((TS_EXP) << SCMI_TELEMETRY_DE_TIMESTAMP_EXP_POS) & \ + SCMI_TELEMETRY_DE_TIMESTAMP_EXP_MASK) | \ + (((TS_SUPPORT) << SCMI_TELEMETRY_DE_TIMESTAMP_SUPPORT_POS) & \ + SCMI_TELEMETRY_DE_TIMESTAMP_SUPPORT_MASK)) + +/*! + * \brief Bit positions for DE attribute fields in `de_attributes_2` + */ +#define SCMI_TELEMETRY_DE_INSTANCE_ID_POS 24 +#define SCMI_TELEMETRY_DE_COMP_INSTANCE_ID_POS 8 +#define SCMI_TELEMETRY_DE_COMP_TYPE_POS 0 + +/* Bit masks for `de_attributes_2` */ +#define SCMI_TELEMETRY_DE_INSTANCE_ID_MASK \ + (UINT32_C(0xFF) << SCMI_TELEMETRY_DE_INSTANCE_ID_POS) +#define SCMI_TELEMETRY_DE_COMP_INSTANCE_ID_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_DE_COMP_INSTANCE_ID_POS) +#define SCMI_TELEMETRY_DE_COMP_TYPE_MASK \ + (UINT32_C(0xFF) << SCMI_TELEMETRY_DE_COMP_TYPE_POS) + +/*! + * \brief Macro to construct `de_attributes_2` field. + * + * \param[in] DE_INSTANCE_ID Unique instance ID + * \param[in] DE_COMP_INSTANCE_ID Component instance ID + * \param[in] DE_COMP_TYPE Component type identifier + * + * \return Encoded `de_attributes_2` field. + */ +#define SCMI_TELEMETRY_DE_ATTR_2( \ + DE_INSTANCE_ID, DE_COMP_INSTANCE_ID, DE_COMP_TYPE) \ + ((((DE_INSTANCE_ID) << SCMI_TELEMETRY_DE_INSTANCE_ID_POS) & \ + SCMI_TELEMETRY_DE_INSTANCE_ID_MASK) | \ + (((DE_COMP_INSTANCE_ID) << SCMI_TELEMETRY_DE_COMP_INSTANCE_ID_POS) & \ + SCMI_TELEMETRY_DE_COMP_INSTANCE_ID_MASK) | \ + (((DE_COMP_TYPE) << SCMI_TELEMETRY_DE_COMP_TYPE_POS) & \ + SCMI_TELEMETRY_DE_COMP_TYPE_MASK)) + +/*! + * \brief SCMI response structure for DE descriptions. + * + * This structure is used in the SCMI Telemetry DE Description response, + * containing the number of available DE descriptions and their descriptors. + */ +struct scmi_telemetry_de_desc_p2a { + int status; /*!< Status of the SCMI request */ + uint32_t num_desc; /*!< Number of DE descriptions in the response */ + struct mod_telemetry_de_desc de_desc[]; /*!< Array of DE descriptors */ +}; + +/*! + * \brief SCMI Telemetry Update Intervals + * + * Defines macros and structures to represent telemetry update intervals + * in the SCMI telemetry protocol. These intervals determine how often + * telemetry data is refreshed. + */ + +/* Bit positions for the update interval fields */ +#define SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_REMAIN_POS \ + 16 /*!< Remaining intervals */ +#define SCMI_TELEMETRY_UPDATE_INTERVALS_FORMAT_POS \ + 12 /*!< Format of the interval */ +#define SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_POS 0 /*!< Number of intervals */ + +/* Bit masks for extracting interval properties */ +#define SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_REMAIN_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_REMAIN_POS) +#define SCMI_TELEMETRY_UPDATE_INTERVALS_FORMAT_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_UPDATE_INTERVALS_FORMAT_POS) +#define SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_MASK \ + (UINT32_C(0xFFF) << SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_POS) + +/*! + * \brief Constructs a telemetry update interval flag. + * + * \param[in] NUM_REMAIN Number of remaining update intervals. + * \param[in] INTERVAL_FORMAT Format of the update intervals (Discrete/Linear). + * \param[in] NUM_INTERVALS Number of update intervals in this response. + * + * \return Encoded update interval flag. + */ +#define SCMI_TELEMETRY_UPDATE_INTERVALS_FLAG( \ + NUM_REMAIN, INTERVAL_FORMAT, NUM_INTERVALS) \ + ((((NUM_REMAIN) << SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_REMAIN_POS) & \ + SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_REMAIN_MASK) | \ + (((INTERVAL_FORMAT) << SCMI_TELEMETRY_UPDATE_INTERVALS_FORMAT_POS) & \ + SCMI_TELEMETRY_UPDATE_INTERVALS_FORMAT_MASK) | \ + (((NUM_INTERVALS) << SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_POS) & \ + SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_MASK)) + +/*! + * \brief SCMI response structure for telemetry update intervals. + * + * This structure is used in the SCMI telemetry response to provide + * a list of available update intervals. + */ +struct scmi_telemetry_list_update_intervals_p2a { + int32_t status; /*!< Status of the SCMI request (SCMI_SUCCESS, etc.) */ + uint32_t flags; /*!< Encoded flags representing update intervals */ +}; + +/*! + * \brief SCMI Telemetry Data Event (DE) Configuration + * + * Defines macros and structures for configuring Data Events (DE) + * in the SCMI telemetry protocol. + */ + +/*! + * \brief Data Event (DE) Modes + * + * These modes specify whether a Data Event is enabled, disabled, + * or enabled with a timestamp. + */ + +#define SCMI_TELEMETRY_DE_DISABLE 0 /*!< Disable Data Event */ +#define SCMI_TELEMETRY_DE_ENABLE_NON_TS \ + 1 /*!< Enable Data Event without timestamp */ +#define SCMI_TELEMETRY_DE_ENABLE_TS 2 /*!< Enable Data Event with timestamp */ + +/*! + * \brief SHMTI ID Constants + * + * These constants indicate unavailable or unsupported SHMTI IDs. + */ +#define SCMI_TELEMETRY_DE_SHMTI_ID_NOT_SUPPORTED UINT32_C(0xFFFFFFFF) +#define SCMI_TELEMETRY_DE_SHMTI_ID_OFFSET_NOT_SUPPORTED UINT32_C(0xFFFFFFFF) + +/*! + * \brief Bit positions and masks for DE configuration flags + */ +#define SCMI_TELEMETRY_DE_CONFIGURE_ALL_DE_DISABLE_POS \ + 2 /*!< Disable flag position */ +#define SCMI_TELEMETRY_DE_CONFIGURE_ALL_DE_DISABLE_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_DE_CONFIGURE_ALL_DE_DISABLE_POS) + +#define SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE_POS 0 /*!< Mode field position */ +#define SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE_MASK \ + (UINT32_C(0x3) \ + << SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE_POS) /*!< Uses 2 bits */ + +/*! + * \brief Check if all DEs are disabled + * + * \param[in] DE_CONFIGURE_FLAGS The flags to check. + * + * \return Nonzero if all DEs are disabled, zero otherwise. + */ +#define SCMI_TELEMETRY_ALL_DE_DISABLED(DE_CONFIGURE_FLAGS) \ + ((DE_CONFIGURE_FLAGS) & SCMI_TELEMETRY_DE_CONFIGURE_ALL_DE_DISABLE_MASK) + +/*! + * \brief Extract DE mode from configuration flags + * + * \param[in] DE_CONFIGURE_FLAGS The flags containing DE mode. + * + * \return The extracted DE mode. + */ +#define SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE(DE_CONFIGURE_FLAGS) \ + (((DE_CONFIGURE_FLAGS) & SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE_MASK) >> \ + SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE_POS) + +/*! + * \brief SHMTI ID Unavailable Constants + * + * These constants indicate that SHMTI IDs and offsets are unavailable. + */ +#define SCMI_TELEMETRY_SHMTI_ID_UNAVAILABLE UINT32_C(0xFFFFFFFF) +#define SCMI_TELEMETRY_SHMTI_ID_OFFSET_UNAVAILABLE UINT32_C(0xFFFFFFFF) + +/*! + * \brief SCMI request structure for DE configuration. + * + * This structure is used in SCMI requests to configure Data Events (DEs). + */ +struct scmi_telemetry_de_configure_a2p { + uint32_t de_id; /*!< ID of the Data Event to configure */ + uint32_t flags; /*!< Configuration flags (enable/disable/mode) */ +}; + +/*! + * \brief SCMI response structure for DE configuration. + * + * This structure is used in SCMI responses to indicate + * the status of a DE configuration request. + */ +struct scmi_telemetry_de_configure_p2a { + int32_t status; /*!< Status of the request (SCMI_SUCCESS, etc.) */ + uint32_t shmti_id; /*!< Assigned SHMTI ID for the Data Event */ + uint32_t shmti_de_offset; /*!< Offset of the Data Event within the SHMTI */ +}; + +/*! + * \brief SCMI Telemetry Enabled Data Events List + * + * Defines macros, enums, and structures used to retrieve a list of + * enabled Data Events (DE) in SCMI Telemetry. + */ + +/*! \brief Bit position and mask for the number of remaining DEs */ +#define SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_REMAIN_POS 16 +#define SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_REMAIN_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_REMAIN_POS) + +/*! \brief Bit position and mask for the number of DEs in response */ +#define SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_POS 0 +#define SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_POS) + +/*! + * \brief Macro to construct the enabled DE list flag. + * + * \param[in] NUM_REMAIN Number of remaining enabled DEs. + * \param[in] NUM_DE Number of DEs in the current response. + * + * \return Encoded flag representing the DE list response. + */ +#define SCMI_TELEMETRY_DE_ENABLED_LIST_FLAG(NUM_REMAIN, NUM_DE) \ + ((((NUM_REMAIN) << SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_REMAIN_POS) & \ + SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_REMAIN_MASK) | \ + (((NUM_DE) << SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_POS) & \ + SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_MASK)) + +/*! + * \brief Enumeration for Data Event timestamp modes. + * + * Used to specify whether timestamps are enabled or disabled for a DE. + */ +#define SCMI_TELEMETRY_DE_TS_DISABLED 1U /*!< Timestamp disabled */ +#define SCMI_TELEMETRY_DE_TS_ENABLED 2U /*!< Timestamp enabled */ + +/*! + * \brief Response structure for enabled DE list. + * + * Contains the list of enabled Data Events and relevant flags. + */ +struct scmi_telemetry_de_enabled_list_p2a { + int status; /*!< Status of the SCMI request (SCMI_SUCCESS, etc.) */ + uint32_t flags; /*!< Encoded flags indicating DE count information */ + struct mod_telemetry_de_status array[]; /*!< Array of enabled DE statuses */ +}; + +/*! + * \brief SCMI Telemetry Configuration Macros + * + * These macros define the control parameters for configuring + * telemetry settings such as sampling rate and operational modes. + */ + +/*! \brief Bit position and mask for enabling/disabling telemetry */ +#define SCMI_TELEMETRY_CONFIG_CONTROL_EN_POS 0 +#define SCMI_TELEMETRY_CONFIG_CONTROL_EN_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_CONFIG_CONTROL_EN_POS) + +/*! \brief Bit position and mask for configuring telemetry mode */ +#define SCMI_TELEMETRY_CONFIG_CONTROL_MODE_POS 1 +#define SCMI_TELEMETRY_CONFIG_CONTROL_MODE_MASK \ + (UINT32_C(0xF) << SCMI_TELEMETRY_CONFIG_CONTROL_MODE_POS) + +/*! + * \brief Extracts telemetry control mode from configuration flags. + * + * \param[in] CONTROL_VAL The control value containing mode settings. + * + * \return The extracted telemetry control mode. + */ +#define SCMI_TELEMETRY_CONFIG_SET_CONTROL_MODE(CONTROL_VAL) \ + (((CONTROL_VAL) & SCMI_TELEMETRY_CONFIG_CONTROL_MODE_MASK) >> \ + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_POS) + +/*! + * \brief Constructs telemetry control settings. + * + * \param[in] MODE Telemetry mode to configure. + * \param[in] EN Enable (1) or disable (0) telemetry. + * + * \return Encoded control value for telemetry settings. + */ +#define SCMI_TELEMETRY_CONFIG_SET_CONTROL_FLAGS(MODE, EN) \ + ((((MODE) << SCMI_TELEMETRY_CONFIG_CONTROL_MODE_POS) & \ + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_MASK) | \ + (((EN) << SCMI_TELEMETRY_CONFIG_CONTROL_EN_POS) & \ + SCMI_TELEMETRY_CONFIG_CONTROL_EN_MASK)) + +/*! + * \brief Macros for setting telemetry sampling rate. + * + * Defines bit positions and masks for configuring the telemetry sampling rate. + */ + +/*! \brief Bit position and mask for specifying sampling rate in seconds */ +#define SCMI_TELEMETRY_SAMPLING_RATE_SEC_POS 5 +#define SCMI_TELEMETRY_SAMPLING_RATE_SEC_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_SAMPLING_RATE_SEC_POS) + +/*! \brief Bit position and mask for exponent in sampling rate */ +#define SCMI_TELEMETRY_SAMPLING_RATE_EXP_POS 0 +/*! + * \brief Max for exponent in sampling rate + * \note Since exponent can be a negative value, left shift or right shift + * using field position can not be done as shift on some compilers + * are not defined + */ +#define SCMI_TELEMETRY_SAMPLING_RATE_EXP_MASK (UINT32_C(0x1F)) + +/*! + * \brief Constructs the telemetry sampling rate value. + * + * \param[in] SEC Sampling rate in seconds. + * \param[in] EXP Exponent for scaling the sampling rate. + * + * \return Encoded sampling rate value. + */ +#define SCMI_TELEMETRY_SAMPLING_RATE(SEC, EXP) \ + ((((SEC) << SCMI_TELEMETRY_SAMPLING_RATE_SEC_POS) & \ + SCMI_TELEMETRY_SAMPLING_RATE_SEC_MASK) | \ + (((EXP)) & SCMI_TELEMETRY_SAMPLING_RATE_EXP_MASK)) + +/*! + * \brief Enumeration for telemetry configuration control modes. + * + * Defines the possible operation modes for telemetry data collection. + */ +enum scmi_telemetry_config_control_modes { + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_SHMTI = 0, /*!< Use SHMTI */ + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_NOTIFICATIONS = + 1, /*!< Use notifications */ + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_ASYNC_READ = 2, /*!< Use async read */ +}; + +/*! + * \brief Request structure for telemetry configuration settings. + * + * This structure is used in SCMI requests to set telemetry configuration. + */ +struct scmi_telemetry_config_set_a2p { + uint32_t control; /*!< Encoded control flags (mode, enable/disable) */ + uint32_t sampling_rate; /*!< Encoded sampling rate value */ +}; + +/*! + * \brief Response structure for telemetry configuration settings. + * + * This structure is used in SCMI responses to confirm telemetry settings. + */ +struct scmi_telemetry_config_set_p2a { + int32_t status; /*!< Status of the request (SCMI_SUCCESS, etc.) */ +}; + +/*! + * \brief Response structure for retrieving telemetry configuration. + * + * This structure is used in SCMI responses to fetch the current + * telemetry configuration settings. + */ +struct scmi_telemetry_config_get_p2a { + int32_t status; /*!< Status of the request */ + uint32_t control; /*!< Current control settings */ + uint32_t sampling_rate; /*!< Current sampling rate settings */ +}; + +/*! + * \} + */ + +/*! + * \} + */ + +#endif /* INTERNAL_SCMI_TELEMETRY_H */ diff --git a/module/scmi_telemetry/include/mod_scmi_telemetry.h b/module/scmi_telemetry/include/mod_scmi_telemetry.h new file mode 100644 index 000000000..2c062a0b0 --- /dev/null +++ b/module/scmi_telemetry/include/mod_scmi_telemetry.h @@ -0,0 +1,145 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * SCMI Telemetry Protocol Support. + */ + +#ifndef MOD_SCMI_TELEMETRY_H +#define MOD_SCMI_TELEMETRY_H + +#include + +#include + +#include +#include + +/*! + * \ingroup GroupModules + * \defgroup GroupSCMI_TELEMETRY SCMI Telemetry Management Protocol + * \{ + */ + +/*! + * \brief Permission flags governing the ability to use certain SCMI commands + * to interact with a telemetry device. + */ + +/*! No permissions (at least one must be granted) */ +#define MOD_SCMI_TELEMETRY_PERM_INVALID 0UL + +/*! The telemetry device's attributes can be queried */ +#define MOD_SCMI_TELEMETRY_PERM_ATTRIBUTES (1U << 0) + +/*! The permission to access telemetry data */ +#define MOD_SCMI_TELEMETRY_PERM_TELEMETRY (1U << 1) + +/*! + * \brief Telemetry device structure. + * + * \details This structure is used in per-agent telemetry device tables. + * Each device contains an identifier for an element that implements the + * telemetry API. + */ +struct mod_scmi_telemetry_device { + /*! Telemetry element identifier */ + fwk_id_t telemetry_source_id; + + /*! Permissions mask (defined by telemetry device configuration) */ + uint8_t permissions; +}; + +/*! + * \brief SCMI Agent descriptor. + * + * \details Describes an SCMI agent using the telemetry protocol. + * It provides a list of accessible telemetry devices. + */ +struct mod_scmi_telemetry_agent { + /*! Pointer to telemetry device table for this agent */ + const struct mod_scmi_telemetry_device *device_table; + + /*! Number of devices in the agent's telemetry table */ + uint8_t agent_device_count; +}; + +/*! + * \brief SCMI Telemetry module configuration. + */ +struct mod_scmi_telemetry_config { + /*! + * \brief Pointer to agent descriptors table. + * Each entry provides a per-agent view of telemetry devices. + */ + const struct mod_scmi_telemetry_agent *agent_table; + + /*! Number of agents in the system */ + uint32_t agent_count; + + /*! Attributes supported by SCMI telemetry protocol */ + uint32_t attributes; +}; + +/*! + * \brief SCMI Telemetry API indices. + */ +enum scmi_telemetry_api_idx { + /*! Index for the SCMI protocol API */ + MOD_SCMI_TELEMETRY_PROTOCOL_API, + + /*! Number of APIs */ + MOD_SCMI_TELEMETRY_API_COUNT +}; + +/*! + * \defgroup GroupScmiTelemetryPolicyHandler SCMI Telemetry Policy Handler + * \brief Policy handlers for SCMI Telemetry. + * + * \details SCMI policy handlers allow platforms to enforce specific policies. + * These handlers may be overridden in platform-specific implementations. + * + * \{ + */ + +/*! + * \brief Policy handler return values. + * + * \details These values determine whether the SCMI message handler should + * proceed with processing or reject the request. + */ +enum mod_scmi_telemetry_policy_status { + /*! Reject the request */ + MOD_SCMI_TELEMETRY_SKIP_MESSAGE_HANDLER, + + /*! Process the request */ + MOD_SCMI_TELEMETRY_EXECUTE_MESSAGE_HANDLER, +}; + +/*! + * \brief SCMI Telemetry Request Policy. + * + * \details This function determines whether the telemetry request should be + * granted or rejected. The policy handler is executed before message + * processing. + * + * \param[out] policy_status Resulting policy status. + * \param[in] agent_id Identifier of the requesting SCMI agent. + * \param[in] device_id Identifier of the telemetry device. + * + * \retval FWK_SUCCESS Operation succeeded. + * \return Other FWK_* error codes. + */ +int scmi_telemetry_telemetry_request_policy( + enum mod_scmi_telemetry_policy_status *policy_status, + uint32_t agent_id, + uint32_t device_id); + +/*! + * \} + */ + +#endif /* MOD_SCMI_TELEMETRY_H */ diff --git a/module/scmi_telemetry/src/mod_scmi_telemetry.c b/module/scmi_telemetry/src/mod_scmi_telemetry.c new file mode 100644 index 000000000..c258e9540 --- /dev/null +++ b/module/scmi_telemetry/src/mod_scmi_telemetry.c @@ -0,0 +1,1548 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * SCMI Telemetry management protocol support. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef BUILD_HAS_MOD_RESOURCE_PERMS +# include +#endif + +/*! + * \brief SCMI Telemetry context structure. + * + * This structure holds the context for SCMI telemetry, including configuration, + * APIs, and various operational parameters. + */ +struct scmi_telemetry_context { + /*! SCMI Telemetry Configuration */ + const struct mod_scmi_telemetry_config *config; + + /*! Pointer to the bound SCMI protocol API */ + const struct mod_scmi_from_protocol_api *scmi_api; + + /*! Pointer to the telemetry protocol support API */ + const struct mod_telemetry_protocol_support_api *telemetry_api; + + /*! Flag to indicate if telemetry is enabled */ + bool telemetry_enable; + + /*! Current telemetry sampling rate */ + uint32_t current_sampling_rate; + + /*! Pointer to the table storing telemetry agents */ + struct mod_scmi_telemetry_agent *agent_table; + +#ifdef BUILD_HAS_SCMI_NOTIFICATIONS + /*! SCMI notification ID */ + fwk_id_t notification_id; + + /*! Pointer to the SCMI notification API */ + const struct mod_scmi_notification_api *scmi_notification_api; +#endif + +#ifdef BUILD_HAS_MOD_RESOURCE_PERMS + /*! Pointer to the SCMI telemetry permissions API */ + const struct mod_scmi_telemetry_permissions_api *perms_api; +#endif +}; + +/*! + * Function prototypes for handling various SCMI telemetry protocol commands. + * Each function processes a specific SCMI message type and responds + * accordingly. + */ +static int protocol_version_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles SCMI Protocol Version request */ + +static int negotiate_protocol_version_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles SCMI Protocol Version negotiation */ + +static int protocol_attributes_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles SCMI Protocol Attributes request */ + +static int protocol_message_attributes_handler( + fwk_id_t service_id, + const uint32_t + *payload); /*!< Handles SCMI Protocol Message Attributes request */ + +static int scmi_telemetry_list_shmti_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles retrieval of SHMTI list */ + +static int scmi_telemetry_de_description_handler( + fwk_id_t service_id, + const uint32_t + *payload); /*!< Handles retrieval of Data Event (DE) description */ + +static int scmi_telemetry_list_update_intervals_handler( + fwk_id_t service_id, + const uint32_t + *payload); /*!< Handles retrieval of available update intervals */ + +static int scmi_telemetry_de_configure_handler( + fwk_id_t service_id, + const uint32_t + *payload); /*!< Handles configuration of a specific Data Event (DE) */ + +static int scmi_telemetry_de_enabled_list_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Retrieves the list of enabled Data Events */ + +static int scmi_telemetry_config_set_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles setting telemetry configuration */ + +static int scmi_telemetry_config_get_handler( + fwk_id_t service_id, + const uint32_t + *payload); /*!< Handles retrieval of current telemetry configuration */ + +#ifdef BUILD_HAS_SCMI_NOTIFICATIONS +static int scmi_telemetry_notify_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles sending telemetry notifications */ +#endif + +/*! + * Internal variables + * These store context and lookup tables for handling telemetry-related + * messages. + */ + +static struct scmi_telemetry_context + scmi_telemetry_ctx; /*!< Global context for SCMI telemetry */ + +/*! + * Lookup table mapping SCMI message types to their corresponding handlers. + * This allows efficient dispatch of incoming SCMI messages. + */ +static handler_table_t msg_handler_table[] = { + [MOD_SCMI_PROTOCOL_VERSION] = protocol_version_handler, + [MOD_SCMI_PROTOCOL_ATTRIBUTES] = protocol_attributes_handler, + [MOD_SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = + protocol_message_attributes_handler, + [MOD_SCMI_TELEMETRY_LIST_SHMTI] = scmi_telemetry_list_shmti_handler, + [MOD_SCMI_TELEMETRY_DE_DESCRIPTION] = scmi_telemetry_de_description_handler, + [MOD_SCMI_TELEMETRY_LIST_UPDATE_INTERVALS] = + scmi_telemetry_list_update_intervals_handler, + [MOD_SCMI_TELEMETRY_DE_CONFIGURE] = scmi_telemetry_de_configure_handler, + [MOD_SCMI_TELEMETRY_DE_ENABLED_LIST] = + scmi_telemetry_de_enabled_list_handler, + [MOD_SCMI_TELEMETRY_CONFIG_SET] = scmi_telemetry_config_set_handler, + [MOD_SCMI_TELEMETRY_CONFIG_GET] = scmi_telemetry_config_get_handler, + [MOD_SCMI_NEGOTIATE_PROTOCOL_VERSION] = negotiate_protocol_version_handler, +}; + +/*! + * Lookup table defining expected payload sizes for each SCMI message type. + * Used to validate incoming SCMI messages. + */ +static size_t payload_size_table[] = { + [MOD_SCMI_PROTOCOL_VERSION] = 0, /*!< No payload for version request */ + [MOD_SCMI_PROTOCOL_ATTRIBUTES] = + 0, /*!< No payload for attributes request */ + [MOD_SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = + (unsigned int)sizeof(struct scmi_protocol_message_attributes_a2p), + [MOD_SCMI_TELEMETRY_LIST_SHMTI] = (unsigned int)sizeof(uint32_t), + [MOD_SCMI_TELEMETRY_DE_DESCRIPTION] = (unsigned int)sizeof(uint32_t), + [MOD_SCMI_TELEMETRY_LIST_UPDATE_INTERVALS] = (unsigned int)sizeof(uint32_t), + [MOD_SCMI_TELEMETRY_DE_CONFIGURE] = + (unsigned int)sizeof(struct scmi_telemetry_de_configure_a2p), + [MOD_SCMI_TELEMETRY_DE_ENABLED_LIST] = (unsigned int)sizeof(uint32_t), + [MOD_SCMI_TELEMETRY_CONFIG_SET] = + (unsigned int)sizeof(struct scmi_telemetry_config_set_a2p), + [MOD_SCMI_TELEMETRY_CONFIG_GET] = + 0, /*!< No payload for telemetry config get request */ + [MOD_SCMI_NEGOTIATE_PROTOCOL_VERSION] = (unsigned int)sizeof( + struct scmi_telemetry_negotiate_protocol_version_a2p), +}; + +/* Ensure the message and payload size tables are consistent */ +static_assert( + FWK_ARRAY_SIZE(msg_handler_table) == FWK_ARRAY_SIZE(payload_size_table), + "[SCMI] telemetry protocol table sizes are not consistent"); + +/*! + * SCMI Telemetry protocol implementation + */ + +static int protocol_version_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + struct scmi_protocol_version_p2a outmsg = { + .status = (int32_t)SCMI_SUCCESS, + .version = SCMI_PROTOCOL_VERSION_TELEMETRY, + }; + + return scmi_telemetry_ctx.scmi_api->respond( + service_id, &outmsg, sizeof(outmsg)); +} + +static int protocol_attributes_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + struct scmi_telemetry_protocol_attributes_p2a outmsg = { + .status = (int32_t)SCMI_SUCCESS, + }; + + int status; + unsigned int agent_id; + + /* Retrieve agent ID associated with the service */ + status = scmi_telemetry_ctx.scmi_api->get_agent_id(service_id, &agent_id); + if (status != FWK_SUCCESS) { + return status; + } + + /* Validate agent ID */ + if (agent_id >= scmi_telemetry_ctx.config->agent_count) { + return FWK_E_PARAM; + } + + /* Retrieve the total number of Data Events (DEs) */ + status = scmi_telemetry_ctx.telemetry_api->get_num_de(&outmsg.num_de); + if (status != FWK_SUCCESS) { + return status; + } + + /* Assign protocol attributes */ + outmsg.attributes = scmi_telemetry_ctx.config->attributes; + + /* Respond to the request */ + return scmi_telemetry_ctx.scmi_api->respond( + service_id, &outmsg, sizeof(outmsg)); +} + +static int protocol_message_attributes_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + struct scmi_protocol_message_attributes_p2a outmsg = { + .status = (int32_t)SCMI_NOT_FOUND, + }; + + if (payload == NULL) { + return FWK_E_PARAM; + } + + size_t outmsg_size = sizeof(outmsg.status); + struct scmi_protocol_message_attributes_a2p params; + + /* Copy payload data */ + params = *(const struct scmi_protocol_message_attributes_a2p *)payload; + + /* Validate message ID and check if a handler exists */ + if ((params.message_id <= MOD_SCMI_NEGOTIATE_PROTOCOL_VERSION) && + (msg_handler_table[params.message_id] != NULL)) { + outmsg.status = (int32_t)SCMI_SUCCESS; + outmsg_size = sizeof(outmsg); + } + + /* Respond with the attributes */ + return scmi_telemetry_ctx.scmi_api->respond( + service_id, &outmsg, outmsg_size); +} + +#ifdef RESOURCE_PERMISSION +/*! + * \brief Retrieves the agent identifier associated with a given service. + * + * @param[in] service_id The SCMI service identifier. + * @param[out] agent_id Pointer to store the retrieved agent ID. + * + * @return FWK_SUCCESS The operation was successful. + * @return FWK_E_PARAM Invalid agent ID or service ID. + */ +static int get_agent_id(fwk_id_t service_id, unsigned int *agent_id) +{ + int status; + + if (agent_id == NULL) { + return FWK_E_PARAM; + } + + status = scmi_telemetry_ctx.scmi_api->get_agent_id(service_id, agent_id); + if (status != FWK_SUCCESS) { + return status; + } + + if (*agent_id >= scmi_telemetry_ctx.config->agent_count) { + return FWK_E_PARAM; + } + + return FWK_SUCCESS; +} + +/* + * \brief Retrieves the agent entry from the agent table based on the service + * ID. + * + * @param[in] service_id The SCMI service identifier. + * @param[out] agent Pointer to store the retrieved agent entry. + * + * @return FWK_SUCCESS The operation was successful. + * @return FWK_E_PARAM Invalid service ID or agent entry. + */ +static int get_agent_entry( + fwk_id_t service_id, + const struct mod_scmi_telemetry_agent **agent) +{ + int status; + unsigned int agent_id; + + if (agent == NULL) { + return FWK_E_PARAM; + } + + status = get_agent_id(service_id, &agent_id); + if (status != FWK_SUCCESS) { + return status; + } + + *agent = &scmi_telemetry_ctx.config->agent_table[agent_id]; + + return FWK_SUCCESS; +} + +/*! + * \brief Handles the request policy for SCMI telemetry. + * + * This function defines the default policy behavior for handling telemetry + * requests. It sets the policy status to execute the message handler. + * + * @param[out] policy_status The policy status to be executed. + * @param[out] mode Pointer to store the telemetry mode (optional). + * @param[out] other_params Pointer to store any other param (optional). + * @param[in] agent_id The agent ID requesting the reset. + * @param[in] domain_id The domain ID for which the reset is requested. + * + * @return FWK_SUCCESS The operation was successful. + */ +FWK_WEAK int scmi_telemetry_reset_request_policy( + enum mod_scmi_telemetry_policy_status *policy_status, + enum mod_telemetry_mode *mode, + uint32_t *other_params, + uint32_t agent_id, + uint32_t domain_id) +{ + if (policy_status == NULL) { + return FWK_E_PARAM; + } + + *policy_status = MOD_SCMI_TELEMETRY_EXECUTE_MESSAGE_HANDLER; + + return FWK_SUCCESS; +} +#endif + +/*! + * \brief Determines the maximum number of objects that can fit in a payload. + * + * This function calculates how many objects can be included in a single SCMI + * telemetry response payload, given the maximum payload size. + * + * @param[in] service_id SCMI service identifier. + * @param[in] header_size Size of the response header. + * @param[in] object_size Size of each individual object. + * @param[in, out] remain_count Pointer to the remaining number of objects. + * Updated to reflect the number of objects left after processing. + * @param[out] total_count Pointer to store the computed number of objects + * that can be included in the response payload. + * + * @return FWK_SUCCESS If the operation is successful. + * @return FWK_E_RANGE If there are no remaining objects to process. + * @return FWK_E_SIZE If the payload size is too small to fit any objects. + */ +static int max_objects_in_payload( + fwk_id_t service_id, + size_t header_size, + size_t object_size, + uint32_t *remain_count, + uint32_t *total_count) +{ + int status; + size_t max_payload_size; + uint32_t total_remaining = 0; + uint32_t count = 0; + + /* Ensure valid output parameters */ + if (remain_count == NULL || total_count == NULL || object_size == 0) { + return FWK_E_PARAM; + } + + *total_count = 0; + total_remaining = *remain_count; + + /* Check if there are objects left to process */ + if (total_remaining == 0) { + return FWK_E_RANGE; + } + + /* + * Get the maximum payload size to determine how many entries can + * be returned in one response. + */ + status = scmi_telemetry_ctx.scmi_api->get_max_payload_size( + service_id, &max_payload_size); + if (status != FWK_SUCCESS) { + return status; + } + + /* Ensure payload can accommodate at least the header */ + if (max_payload_size < header_size) { + return FWK_E_SIZE; + } + + max_payload_size -= header_size; + count = max_payload_size / object_size; + + /* Ensure count does not exceed remaining objects */ + count = (uint32_t)FWK_MIN(count, total_remaining); + + /* If count is zero, the payload size is too small */ + if (count == 0) { + return FWK_E_SIZE; + } + + /* Update the remaining count and total count */ + *remain_count = total_remaining - count; + *total_count = count; + + return FWK_SUCCESS; +} + +/*! + * \brief Handles retrieval of SHMTI list for SCMI Telemetry. + * + * This function processes the request to retrieve SHMTI descriptors available + * in the telemetry system. It ensures correct indexing, payload handling, and + * response formatting. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing the index. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_OUT_OF_RANGE If the requested index is out of range. + * @return FWK_E_PARAM If an invalid parameter is provided. + */ +static int scmi_telemetry_list_shmti_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + int status; + size_t i; + uint32_t index; + uint32_t num_shmti; + struct mod_telemetry_shmti_desc shmti_desc; + uint32_t count; + uint32_t remain_count; + int respond_status; + + struct scmi_telemetry_list_shmti_p2a return_values = { + .status = SCMI_GENERIC_ERROR + }; + + uint32_t payload_size = sizeof(return_values); + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + index = *payload; + + /* Retrieve the total number of SHMTI regions */ + status = scmi_telemetry_ctx.telemetry_api->get_num_shmti(&num_shmti); + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Validate the requested index */ + if (index >= num_shmti) { + return_values.status = SCMI_NOT_FOUND; + goto exit; + } + + remain_count = num_shmti - index; + + /* Determine the maximum number of entries that can fit in the response + * payload */ + status = max_objects_in_payload( + service_id, + sizeof(struct scmi_telemetry_list_shmti_p2a), + sizeof(struct mod_telemetry_shmti_desc), + &remain_count, + &count); + + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Iterate through the SHMTI entries and add them to the response */ + for (i = 0; i < count; i++, index++) { + status = + scmi_telemetry_ctx.telemetry_api->get_shmti(index, &shmti_desc); + if (status != FWK_SUCCESS) { + goto exit; + } + + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, payload_size, &shmti_desc, sizeof(shmti_desc)); + if (status != FWK_SUCCESS) { + goto exit; + } + + payload_size += sizeof(shmti_desc); + } + + return_values.status = SCMI_SUCCESS; + return_values.num_shmti = + SCMI_TELEMETRY_LIST_SHMTI_TOTAL_SHMTI(remain_count, count); + + /* Write the final response data */ + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, 0, &return_values, sizeof(return_values)); + +exit: + /* Send response, handling both success and error cases */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, + (return_values.status == SCMI_SUCCESS) ? NULL : &return_values.status, + (return_values.status == SCMI_SUCCESS) ? payload_size : + sizeof(return_values.status)); + + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Failed response in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Handles retrieval of Data Event (DE) descriptions for SCMI Telemetry. + * + * This function processes a request to retrieve descriptions of telemetry + * Data Events (DEs). It ensures proper indexing, payload handling, and response + * formatting. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing the index. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_OUT_OF_RANGE If the requested index is out of range. + * @return FWK_E_PARAM If an invalid parameter is provided. + */ +static int scmi_telemetry_de_description_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + size_t i; + uint32_t num_de; + uint32_t de_desc_index; + uint32_t count, remain_count; + struct mod_telemetry_de_desc de_desc; + struct scmi_telemetry_de_desc_p2a return_values = { + .status = SCMI_GENERIC_ERROR + }; + + uint32_t payload_size = sizeof(return_values); + int status = FWK_SUCCESS; + int respond_status; + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + /* Extract Data Event description index */ + de_desc_index = *(const uint32_t *)payload; + + /* Retrieve total number of Data Events */ + status = scmi_telemetry_ctx.telemetry_api->get_num_de(&num_de); + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Validate the requested index */ + if (de_desc_index >= num_de) { + return_values.status = SCMI_NOT_FOUND; + goto exit; + } + + remain_count = num_de - de_desc_index; + + /* Determine the maximum number of entries that can fit in the response + * payload */ + status = max_objects_in_payload( + service_id, + sizeof(struct scmi_telemetry_de_desc_p2a), + sizeof(struct mod_telemetry_de_desc), + &remain_count, + &count); + + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Iterate through the DE descriptors and add them to the response */ + for (i = 0; i < count; i++, de_desc_index++) { + status = + scmi_telemetry_ctx.telemetry_api->get_de(de_desc_index, &de_desc); + if (status != FWK_SUCCESS) { + goto exit; + } + + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, payload_size, &de_desc, sizeof(de_desc)); + if (status != FWK_SUCCESS) { + goto exit; + } + + payload_size += sizeof(de_desc); + } + + /* Populate response values */ + return_values.num_desc = SCMI_TELEMETRY_DE_DESC_TOTAL(remain_count, count); + return_values.status = SCMI_SUCCESS; + + /* Write the final response data */ + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, 0, &return_values, sizeof(return_values)); + +exit: + /* Send response, handling both success and error cases */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, + (return_values.status == SCMI_SUCCESS) ? NULL : &return_values.status, + (return_values.status == SCMI_SUCCESS) ? payload_size : + sizeof(return_values.status)); + + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Response failed in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Encodes an update interval in SCMI telemetry format. + * + * This function encodes a telemetry sampling interval (e.g. in milliseconds) + * into the SCMI-defined format for update intervals. The encoded interval + * consists of: + * - A number of seconds (left-shifted into its field position), + * - An exponent value (bit-masked into its field). + * + * The format complies with the SCMI specification for telemetry update + * intervals. + * + * \param[in] seconds_base Sampling interval e.g. in milliseconds. + * \param[in] exponent Exponent value (base-10), typically negative (e.g., -3). + * This determines the resolution of the interval. + * + * \retval Encoded interval value combining seconds and exponent. + * \retval 0 If the seconds value exceeds the allowed bit field range. + */ +static uint32_t encode_interval(uint32_t seconds_base, int8_t exponent) +{ + uint32_t seconds_field; + uint32_t exponent_field; + + /* Shift seconds to proper bit position */ + seconds_field = seconds_base << MOD_TELEMETRY_INTERVAL_SECONDS_POS; + + /* Validate seconds field fits within defined mask */ + if (seconds_field & ~(MOD_TELEMETRY_INTERVAL_NUM_SECONDS_MASK)) { + return 0; /* Indicate error */ + } + + /* + * Cast exponent to unsigned and apply bitmask. + * Assumes two's complement representation. + */ + exponent_field = + ((uint32_t)exponent) & MOD_TELEMETRY_INTERVAL_NUM_EXPONENT_MASK; + + /* Combine the shifted seconds and masked exponent */ + return seconds_field | exponent_field; +} + +/*! + * \brief Handles retrieval of available update intervals for SCMI Telemetry. + * + * This function processes a request to retrieve a list of available update + * intervals for telemetry data refresh. It ensures correct indexing, payload + * handling, and response formatting. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing the index. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_OUT_OF_RANGE If the requested index is out of range. + * @return FWK_E_PARAM If an invalid parameter is provided. + */ +static int scmi_telemetry_list_update_intervals_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + size_t i; + uint32_t num_intervals; + /* Index received from the agent as part of the payload */ + uint32_t index, count, remain_count; + + uint32_t sampling_rate; + uint32_t interval; + enum mod_telemetry_update_interval_formats interval_format; + + struct scmi_telemetry_list_update_intervals_p2a return_values = { + .status = SCMI_GENERIC_ERROR + }; + + uint32_t payload_size = sizeof(return_values); + int status = FWK_SUCCESS; + int respond_status; + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + /* Extract index from the payload */ + index = *payload; + + /* Retrieve available update interval information */ + status = scmi_telemetry_ctx.telemetry_api->get_update_intervals_info( + &num_intervals, &interval_format); + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Validate the requested index */ + if (index >= num_intervals) { + return_values.status = SCMI_NOT_FOUND; + goto exit; + } + + remain_count = num_intervals - index; + + /*! + * Determine the maximum number of entries that can fit in the response + * payload + */ + status = max_objects_in_payload( + service_id, + sizeof(struct scmi_telemetry_list_update_intervals_p2a), + sizeof(uint32_t), + &remain_count, + &count); + if (status != FWK_SUCCESS) { + goto exit; + } + + /*! + * Iterate through the available update intervals and add them to the + * response + */ + for (i = 0; i < count; i++, index++) { + status = scmi_telemetry_ctx.telemetry_api->get_update_interval( + index, &sampling_rate); + + if (status != FWK_SUCCESS) { + goto exit; + }; + + interval = encode_interval(sampling_rate, -3); + + if (interval == 0) { + return_values.status = SCMI_OUT_OF_RANGE; + goto exit; + } + + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, payload_size, &interval, sizeof(interval)); + if (status != FWK_SUCCESS) { + goto exit; + } + payload_size += sizeof(interval); + } + + /* Populate response values */ + return_values.status = (int32_t)SCMI_SUCCESS; + return_values.flags = SCMI_TELEMETRY_UPDATE_INTERVALS_FLAG( + remain_count, interval_format, count); + + /* Write the final response data */ + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, 0, &return_values, sizeof(return_values)); + +exit: + /* Send response, handling both success and error cases */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, + (return_values.status == SCMI_SUCCESS) ? NULL : &return_values.status, + (return_values.status == SCMI_SUCCESS) ? payload_size : + sizeof(return_values.status)); + + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Response failed in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Handles the configuration of a specific Data Event (DE) for SCMI + * Telemetry. + * + * This function processes a request to enable or disable a telemetry Data Event + * (DE). It ensures proper validation of the DE ID and flags, applies the + * required configuration, and formats the response accordingly. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing DE + * configuration. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_INVALID_PARAMETERS If invalid flags or DE ID are provided. + * @return FWK_E_PARAM If an invalid parameter is detected. + */ +static int scmi_telemetry_de_configure_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + int status; + int respond_status; + uint32_t de_id; + uint32_t flags; + uint32_t response_size; + + struct scmi_telemetry_de_configure_a2p *params = NULL; + struct scmi_telemetry_de_configure_p2a return_values = { + .status = SCMI_GENERIC_ERROR, + .shmti_id = SCMI_TELEMETRY_DE_SHMTI_ID_NOT_SUPPORTED, + .shmti_de_offset = SCMI_TELEMETRY_DE_SHMTI_ID_OFFSET_NOT_SUPPORTED, + }; + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + /* Parse request parameters */ + params = (struct scmi_telemetry_de_configure_a2p *)payload; + + de_id = params->de_id; + flags = params->flags; + + /* Check if all DEs should be disabled */ + if (SCMI_TELEMETRY_ALL_DE_DISABLED(flags)) { + if (SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE(flags) != 0) { + status = FWK_E_PARAM; + return_values.status = SCMI_INVALID_PARAMETERS; + goto exit; + } + + status = scmi_telemetry_ctx.telemetry_api->disable_all_de(); + return_values.status = + (status == FWK_SUCCESS) ? SCMI_SUCCESS : SCMI_GENERIC_ERROR; + goto exit; + } + + /* Process DE configuration mode */ + switch (SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE(flags)) { + case SCMI_TELEMETRY_DE_DISABLE: + status = scmi_telemetry_ctx.telemetry_api->disable_de(de_id); + return_values.status = + (status == FWK_SUCCESS) ? SCMI_SUCCESS : SCMI_GENERIC_ERROR; + break; + case SCMI_TELEMETRY_DE_ENABLE_NON_TS: + status = scmi_telemetry_ctx.telemetry_api->enable_de_non_ts(de_id); + return_values.status = + (status == FWK_SUCCESS) ? SCMI_SUCCESS : SCMI_GENERIC_ERROR; + break; + case SCMI_TELEMETRY_DE_ENABLE_TS: + status = scmi_telemetry_ctx.telemetry_api->enable_de_ts(de_id); + return_values.status = + (status == FWK_SUCCESS) ? SCMI_SUCCESS : SCMI_GENERIC_ERROR; + break; + default: + status = FWK_E_PARAM; + return_values.status = SCMI_INVALID_PARAMETERS; + break; + } + +exit: + /* Determine response size */ + response_size = (return_values.status == SCMI_SUCCESS) ? + sizeof(return_values) : + sizeof(return_values.status); + + /* Send response */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, &return_values, response_size); + + /* Log response failure, if any */ + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Response failed in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Retrieves the list of enabled Data Events (DEs) for SCMI Telemetry. + * + * This function processes a request to fetch the list of currently enabled DEs. + * It ensures proper indexing, payload handling, and response formatting. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing the index. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_OUT_OF_RANGE If the requested index is out of range. + * @return FWK_E_PARAM If an invalid parameter is provided. + */ +static int scmi_telemetry_de_enabled_list_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + size_t i; + uint32_t num_de_enabled; + uint32_t index, count, remain_count; + struct mod_telemetry_de_status de_status; + struct scmi_telemetry_de_enabled_list_p2a return_values = { + .status = SCMI_GENERIC_ERROR + }; + + uint32_t de_enabled_value[2]; + + uint32_t payload_size = sizeof(return_values); + int status = FWK_SUCCESS; + int respond_status; + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + /* Get index from parameter */ + index = *payload; + + /* Retrieve the number of currently enabled DEs */ + status = + scmi_telemetry_ctx.telemetry_api->get_num_de_enabled(&num_de_enabled); + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Validate the requested index */ + if (index >= num_de_enabled) { + return_values.status = SCMI_NOT_FOUND; + goto exit; + } + + remain_count = num_de_enabled - index; + + /*! + * Determine the maximum number of entries that can fit in the response + * payload + */ + status = max_objects_in_payload( + service_id, + sizeof(struct scmi_telemetry_de_enabled_list_p2a), + sizeof(de_enabled_value), + &remain_count, + &count); + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Retrieve the list of enabled DEs */ + for (i = 0; i < count; i++, index++) { + status = + scmi_telemetry_ctx.telemetry_api->get_de_enabled(index, &de_status); + if (status != FWK_SUCCESS) { + goto exit; + } + de_enabled_value[0] = de_status.de_id; + de_enabled_value[1] = de_status.de_ts_mode; + + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, + payload_size, + &de_enabled_value[0], + sizeof(de_enabled_value)); + if (status != FWK_SUCCESS) { + goto exit; + } + payload_size += sizeof(de_enabled_value); + } + + /* Populate response values */ + return_values.status = (int32_t)SCMI_SUCCESS; + return_values.flags = + SCMI_TELEMETRY_DE_ENABLED_LIST_FLAG(remain_count, count); + + /* Write the final response data */ + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, 0, &return_values, sizeof(return_values)); + +exit: + /* Send response, handling both success and error cases */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, + (return_values.status == SCMI_SUCCESS) ? NULL : &return_values.status, + (return_values.status == SCMI_SUCCESS) ? payload_size : + sizeof(return_values.status)); + + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Response failed in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Retrieves the multiplier for a given sampling rate. + * + * This function extracts the exponent from the sampling rate and adjusts it + * for conversion. The exponent is extracted using the + * `MOD_TELEMETRY_INTERVAL_EXPONENT` macro and then incremented by 7 to + * account for the `sec * 10^7` conversion. + * + * @param[in] sampling_rate The raw sampling rate value from SCMI. + * + * @return The computed multiplier for converting seconds. + */ +static uint64_t get_sec_multiplier(uint32_t sampling_rate) +{ + struct mod_telemetry_update_interval_exponent exponent; + int32_t val; + + /*! + * Extract and sign-extend the exponent from the sampling rate + * Sign-extend happens automatically due to exponent.value is an + * integer type. + */ + exponent.value = MOD_TELEMETRY_INTERVAL_EXPONENT(sampling_rate); + + val = exponent.value; + + /* + * Adjust the exponent, so that resulting value remain >= 0 + * Note: Extra variable 'var' is required because + * width(5 bits) of exponent.value may not sufficient + * if following operation is done directly on exponent.value + */ + val += 7; + + /* Compute the multiplier using power-of-10 */ + return (uint64_t)__builtin_powi(10, val); +} + +/*! + * \brief Converts a raw SCMI sampling rate to milliseconds. + * + * This function extracts the base seconds component and computes the + * milliseconds equivalent using a multiplier derived from the exponent. + * + * @param[in] sampling_rate The raw sampling rate value from SCMI. + * + * @return The sampling rate in milliseconds. + */ +uint64_t convert_sampling_rate_to_msecs(uint32_t sampling_rate) +{ + uint32_t seconds; + uint64_t sec_multiplier; + + /* Get the multiplier */ + sec_multiplier = get_sec_multiplier(sampling_rate); + + /* Extract the seconds component from the sampling rate */ + seconds = MOD_TELEMETRY_INTERVAL_SECONDS(sampling_rate); + + /* Compute and return the final value in milliseconds + * Since sec_multiplier is adjusted by 10^7 for msec + * conversion divide it by 10^4 effectivly multiply + * by 10^3. + */ + return (seconds * sec_multiplier) / 10000; +} + +/*! + * \brief Handles setting telemetry configuration for SCMI Telemetry. + * + * This function processes a request to enable or disable telemetry, + * sets the sampling rate, and validates the configuration mode. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing configuration + * parameters. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_INVALID_PARAMETERS If an invalid control mode is provided. + * @return SCMI_PROTOCOL_ERROR If enabling/disabling telemetry fails. + */ +static int scmi_telemetry_config_set_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + int status; + int respond_status; + uint32_t response_size; + uint64_t sampling_rate_msec; + + struct scmi_telemetry_config_set_a2p *params = NULL; + struct scmi_telemetry_config_set_p2a return_values = { + .status = SCMI_GENERIC_ERROR, + }; + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + /* Parse request parameters */ + params = (struct scmi_telemetry_config_set_a2p *)payload; + + /* Check if telemetry should be disabled */ + if ((SCMI_TELEMETRY_CONFIG_CONTROL_EN_MASK & params->control) == 0) { + status = scmi_telemetry_ctx.telemetry_api->telemetry_disable(); + if (status != FWK_SUCCESS) { + return_values.status = SCMI_PROTOCOL_ERROR; + } else { + scmi_telemetry_ctx.telemetry_enable = false; + return_values.status = SCMI_SUCCESS; + } + goto exit; + } + + if (SCMI_TELEMETRY_CONFIG_SET_CONTROL_MODE(params->control) != + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_SHMTI) { + return_values.status = SCMI_NOT_SUPPORTED; + status = FWK_E_PARAM; + goto exit; + } + + /* Enable telemetry */ + status = scmi_telemetry_ctx.telemetry_api->telemetry_enable(); + if (status != FWK_SUCCESS) { + return_values.status = SCMI_PROTOCOL_ERROR; + goto exit; + } + + scmi_telemetry_ctx.telemetry_enable = true; + + sampling_rate_msec = convert_sampling_rate_to_msecs(params->sampling_rate); + status = scmi_telemetry_ctx.telemetry_api->set_sampling_rate( + (uint32_t)sampling_rate_msec); + if (status != FWK_SUCCESS) { + return_values.status = SCMI_PROTOCOL_ERROR; + goto exit; + } + scmi_telemetry_ctx.current_sampling_rate = params->sampling_rate; + +exit: + /* Determine response size */ + response_size = (return_values.status == SCMI_SUCCESS) ? + sizeof(return_values) : + sizeof(return_values.status); + + /* Send response */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, &return_values, response_size); + + /* Log response failure */ + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Response failed in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Handles retrieval of current telemetry configuration. + * + * This function processes a request to fetch the current telemetry + * configuration. It returns the current telemetry enable state and the active + * sampling rate. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload (unused in this function). + * + * @return FWK_SUCCESS The operation was successful. + */ +static int scmi_telemetry_config_get_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + int status; + struct scmi_telemetry_config_get_p2a return_values = { + .status = SCMI_SUCCESS, + .control = 0, + .sampling_rate = 0, + }; + + /* Check if telemetry is enabled and set the response accordingly */ + if (scmi_telemetry_ctx.telemetry_enable) { + return_values.control = (1U << SCMI_TELEMETRY_CONFIG_CONTROL_EN_POS); + return_values.sampling_rate = scmi_telemetry_ctx.current_sampling_rate; + } + + /* Send response */ + status = scmi_telemetry_ctx.scmi_api->respond( + service_id, &return_values, sizeof(return_values)); + + return status; +} + +/*! + * \brief Handles the negotiation of SCMI protocol version. + * + * This function is currently not supported and returns `FWK_E_SUPPORT` + * indicating that version negotiation is not implemented. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload (unused). + * + * @return FWK_E_SUPPORT Protocol version negotiation is not supported. + */ +static int negotiate_protocol_version_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + return FWK_E_SUPPORT; +} + +#ifdef BUILD_HAS_MOD_RESOURCE_PERMS +/*! + * \brief Handles SCMI resource permission checks for telemetry. + * + * This function validates whether a given SCMI message has the required + * permissions before it is processed. It currently returns `FWK_E_SUPPORT` + * indicating that the permission check is not implemented. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload. + * @param[in] payload_size Size of the request payload. + * @param[in] message_id The SCMI message identifier. + * + * @return FWK_E_SUPPORT Resource permission checks are not supported. + */ +static int scmi_telemetry_permissions_handler( + fwk_id_t service_id, + const uint32_t *payload, + size_t payload_size, + unsigned int message_id) +{ + return FWK_E_SUPPORT; +} +#endif + +/*! + * \brief Retrieves the SCMI protocol ID for telemetry. + * + * This function returns the protocol ID associated with SCMI telemetry. + * + * @param[in] protocol_id The framework identifier for the protocol. + * @param[out] scmi_protocol_id Pointer to store the SCMI protocol ID. + * + * @return FWK_SUCCESS Operation completed successfully. + */ +static int scmi_telemetry_get_scmi_protocol_id( + fwk_id_t protocol_id, + uint8_t *scmi_protocol_id) +{ + *scmi_protocol_id = MOD_SCMI_PROTOCOL_ID_TELEMETRY; + + return FWK_SUCCESS; +} + +/*! + * \brief Handles incoming SCMI messages for telemetry. + * + * This function validates incoming SCMI telemetry messages and dispatches them + * to their respective handlers based on the message ID. It also ensures that + * any required resource permissions are checked. + * + * @param[in] protocol_id The framework identifier for the SCMI protocol. + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload. + * @param[in] payload_size Size of the request payload. + * @param[in] message_id The SCMI message identifier. + * + * @return FWK_SUCCESS Operation completed successfully. + * @return SCMI_DENIED If the message is denied due to permission restrictions. + * @return SCMI_NOT_SUPPORTED If the message ID is not supported. + */ +static int scmi_telemetry_message_handler( + fwk_id_t protocol_id, + fwk_id_t service_id, + const uint32_t *payload, + size_t payload_size, + unsigned int message_id) +{ + int validation_result; + + /* Validate the SCMI message */ + validation_result = scmi_telemetry_ctx.scmi_api->scmi_message_validation( + MOD_SCMI_PROTOCOL_ID_TELEMETRY, + service_id, + payload, + payload_size, + message_id, + payload_size_table, + (unsigned int)MOD_SCMI_TELEMETRY_COMMAND_COUNT, + msg_handler_table); + +#ifdef BUILD_HAS_MOD_RESOURCE_PERMS + /* Check if the message requires resource permission validation */ + if (message_id >= MOD_SCMI_MESSAGE_ID_ATTRIBUTE) { + if (scmi_telemetry_permissions_handler( + service_id, payload, payload_size, message_id) != FWK_SUCCESS) { + validation_result = SCMI_DENIED; + } + } +#endif + + if (validation_result != SCMI_SUCCESS) { + return scmi_telemetry_ctx.scmi_api->respond( + service_id, &validation_result, sizeof(validation_result)); + } + + /* Dispatch the message to the appropriate handler */ + if (msg_handler_table[message_id] == NULL) { + return FWK_E_PARAM; + } + + return msg_handler_table[message_id](service_id, payload); +} + +/*! + * \brief SCMI telemetry module API structure. + * + * This structure defines the interface for handling SCMI telemetry messages. + */ +static struct mod_scmi_to_protocol_api + scmi_telemetry_mod_scmi_to_protocol_api = { + .get_scmi_protocol_id = scmi_telemetry_get_scmi_protocol_id, + .message_handler = scmi_telemetry_message_handler + }; + +/* + * Framework handlers + */ + +/*! + * \brief Initializes the SCMI telemetry module. + * + * This function initializes the SCMI telemetry module by storing the provided + * configuration data. It ensures that the configuration and agent table are + * valid. + * + * @param[in] module_id The module identifier. + * @param[in] element_count Number of elements in the module (unused). + * @param[in] data Pointer to the module configuration. + * + * @return FWK_SUCCESS Initialization was successful. + * @return FWK_E_PARAM If the configuration data is NULL or the agent table is + * NULL. + */ +static int scmi_telemetry_init( + fwk_id_t module_id, + unsigned int element_count, + const void *data) +{ + const struct mod_scmi_telemetry_config *config; + + if (data == NULL) { + return FWK_E_PARAM; + } + + config = (const struct mod_scmi_telemetry_config *)data; + + if (config->agent_table == NULL) { + return FWK_E_PARAM; + } + + scmi_telemetry_ctx.config = config; + + return FWK_SUCCESS; +} + +#ifdef BUILD_HAS_SCMI_NOTIFICATIONS +/*! + * \brief Initializes SCMI telemetry notifications. + * + * This function is currently not implemented and triggers an assertion failure + * when called. + * + * @return No return, function triggers an assertion failure. + */ +static int scmi_telemetry_init_notifications(void) +{ + fwk_assert(false); +} +#endif + +/*! + * \brief Binds required module dependencies for SCMI telemetry. + * + * This function binds the SCMI protocol API and, if enabled, binds + * the SCMI notification API and telemetry API. + * + * @param[in] id The module identifier. + * @param[in] round The binding round (ensures dependencies are bound in order). + * + * @return FWK_SUCCESS The binding was successful. + * @return FWK_E_PANIC If any of the required bindings fail. + */ +static int scmi_telemetry_bind(fwk_id_t id, unsigned int round) +{ + int status; + + /* Perform binding only in the first round */ + if (round == 1) { + return FWK_SUCCESS; + } + + /* Bind the SCMI protocol API */ + status = fwk_module_bind( + FWK_ID_MODULE(FWK_MODULE_IDX_SCMI), + FWK_ID_API(FWK_MODULE_IDX_SCMI, MOD_SCMI_API_IDX_PROTOCOL), + &scmi_telemetry_ctx.scmi_api); + if (status != FWK_SUCCESS) { + return status; + } + +#ifdef BUILD_HAS_SCMI_NOTIFICATIONS + /* Bind the SCMI notification API */ + status = fwk_module_bind( + FWK_ID_MODULE(FWK_MODULE_IDX_SCMI), + FWK_ID_API(FWK_MODULE_IDX_SCMI, MOD_SCMI_API_IDX_NOTIFICATION), + &scmi_telemetry_ctx.scmi_notification_api); + if (status != FWK_SUCCESS) { + return status; + } +#endif + +#ifdef BUILD_HAS_MOD_TELEMETRY + /* Bind the telemetry protocol API */ + return fwk_module_bind( + FWK_ID_MODULE(FWK_MODULE_IDX_TELEMETRY), + FWK_ID_API(FWK_MODULE_IDX_TELEMETRY, 0), + &scmi_telemetry_ctx.telemetry_api); +#else + return FWK_SUCCESS; +#endif +} + +/*! + * \brief Processes incoming API bind requests. + * + * This function handles bind requests for the SCMI telemetry protocol API. + * + * @param[in] source_id The identifier of the module requesting the API. + * @param[in] target_id The identifier of the module providing the API. + * @param[in] api_id The API identifier. + * @param[out] api Pointer to the requested API. + * + * @return FWK_SUCCESS If the requested API is provided successfully. + * @return FWK_E_ACCESS If the requested API is not available. + */ +static int scmi_telemetry_process_bind_request( + fwk_id_t source_id, + fwk_id_t target_id, + fwk_id_t api_id, + const void **api) +{ + switch ((enum scmi_telemetry_api_idx)fwk_id_get_api_idx(api_id)) { + case MOD_SCMI_TELEMETRY_PROTOCOL_API: + if (api == NULL) { + return FWK_E_PARAM; + } + *api = &scmi_telemetry_mod_scmi_to_protocol_api; + break; + + default: + return FWK_E_ACCESS; + } + + return FWK_SUCCESS; +} + +#if defined(BUILD_HAS_SCMI_NOTIFICATIONS) && defined(BUILD_HAS_NOTIFICATION) +/*! + * \brief Processes received SCMI telemetry notifications. + * + * This function is a stub for handling telemetry notifications. + * + * @param[in] event The received event. + * @param[out] resp_event The response event (if needed). + * + * @return FWK_SUCCESS The function always returns success. + */ +static int scmi_telemetry_process_notification( + const struct fwk_event *event, + struct fwk_event *resp_event) +{ + return FWK_SUCCESS; +} +#endif + +/*! + * \brief SCMI Telemetry Management Protocol Definition. + * + * This structure defines the module type and function handlers + * required for SCMI telemetry management. + */ +const struct fwk_module module_scmi_telemetry = { + .api_count = (unsigned int)MOD_SCMI_TELEMETRY_API_COUNT, + .type = FWK_MODULE_TYPE_PROTOCOL, + .init = scmi_telemetry_init, + .bind = scmi_telemetry_bind, + .process_bind_request = scmi_telemetry_process_bind_request, +#if defined(BUILD_HAS_SCMI_NOTIFICATIONS) && defined(BUILD_HAS_NOTIFICATION) + .process_notification = scmi_telemetry_process_notification, +#endif +}; -- GitLab