From 9bc405dbbd4571fbd5bcb416d525dce0a88ab74f Mon Sep 17 00:00:00 2001 From: Sami Kiminki Date: Fri, 25 Feb 2022 14:31:03 +0200 Subject: [PATCH] gpu: nvgpu: nvs asynchronous control interface 1.0.0 Add asynchronous control interface for the GPU scheduler. The interface consists of: - General FIFO specification - General message send/receive procedures - The initial set of command messages for handshake, domain switching, and error responses JIRA GCSS-1892 Change-Id: Ib86baf470d9fdf2e45f4391faf247006d9b80f0b Signed-off-by: Sami Kiminki Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2675369 Reviewed-by: Debarshi Dutta Reviewed-by: Ankur Kishore --- nvsched/include/nvs/nvs-control-interface.h | 340 +++++++++++++++ nvsched/include/nvs/nvs-control-messages.h | 438 ++++++++++++++++++++ 2 files changed, 778 insertions(+) create mode 100644 nvsched/include/nvs/nvs-control-interface.h create mode 100644 nvsched/include/nvs/nvs-control-messages.h diff --git a/nvsched/include/nvs/nvs-control-interface.h b/nvsched/include/nvs/nvs-control-interface.h new file mode 100644 index 000000000..ce6b96578 --- /dev/null +++ b/nvsched/include/nvs/nvs-control-interface.h @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2022 NVIDIA Corporation. All rights reserved. + * + * NVIDIA Corporation and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA Corporation is strictly prohibited. + */ + +#ifndef NVS_CONTROL_INTERFACE_H +#define NVS_CONTROL_INTERFACE_H + +/** + * @file + * @brief NVIDIA GPU domain scheduler asynchronous messaging interface + */ + +#include "nvs-control-messages.h" + +#if defined(__cplusplus) +#include +#else +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + +/** + * @brief Value for nvs_domain_msg_fifo_control::get to indicate disabled + * flow control. + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_MSG_FIFO_CONTROL_GET_FLOW_CTRL_DISABLED (0xFFFFFFFFU) + +/** + * @brief Least significant bit of field PUT in nvs_domain_msg_fifo_control::put_revolutions + */ +#define NVS_DOMAIN_MSG_FIFO_CONTROL_PUT_REVOLUTIONS_PUT_LSB (0U) + +/** + * @brief Most significant bit of field PUT in nvs_domain_msg_fifo_control::put_revolutions + */ +#define NVS_DOMAIN_MSG_FIFO_CONTROL_PUT_REVOLUTIONS_PUT_MSB (31U) + +/** + * @brief Least significant bit of field REVOLUTIONS in nvs_domain_msg_fifo_control::put_revolutions + */ +#define NVS_DOMAIN_MSG_FIFO_CONTROL_PUT_REVOLUTIONS_REVOLUTIONS_LSB (32U) + +/** + * @brief Most significant bit of field REVOLUTIONS in nvs_domain_msg_fifo_control::put_revolutions + */ +#define NVS_DOMAIN_MSG_FIFO_CONTROL_PUT_REVOLUTIONS_REVOLUTIONS_MSB (63U) + +/** + * @brief The FIFO ring buffer control block + * + * FIFO ring buffer initialization + * ------------------------------- + * + * The FIFO ring buffer control block should be initialized on allocation as + * follows: + * - client --> scheduler: + * - all zeroes + * - scheduler --> client: + * - nvs_domain_msg_fifo_control::get = + * #NVS_DOMAIN_MSG_FIFO_CONTROL_GET_FLOW_CTRL_DISABLED. + * - everything else zeroes + * + * The FIFO size in entries is calculated as follows from the buffer size: + * + * @code + * num_messages = (buffer_size - sizeof(nvs_domain_msg_fifo_control)) / sizeof(nvs_domain_message) + * @endcode + * + * With the current data structure layouts, this formula with sizeof substitutions is as: + * + * @code + * num_messages = (buffer_size - 128U) / 64U + * @endcode + * + * For example, the number of messages in the FIFO is 1022 for a buffer of size 64K. + * + * + * Adding a message in the FIFO ring buffer + * ---------------------------------------- + * + * The sender is suggested to maintain the following variables locally: + * - @c local_put --- local copy of put index + * - @c local_revolution_count --- local copy of revolution count + * - @c local_num_dropped_messages --- local copy of number of dropped messages + * - @c local_fifo_size_entries --- local copy of the FIFO ring buffer size + * + * When the sender is initialized, the local variables should be initialized + * from the fields in #nvs_domain_msg_fifo_control, except for the FIFO size. The + * FIFO size is received from nvgpu-rm as part of the physical buffer + * parameters. + * + * The sequence for adding a message in the FIFO ring buffer is as follows: + * + * 1. Read nvs_domain_msg_fifo_control::get as @c get + * 2. Determine whether there is space for the message. There are two cases: + * - @c get == #NVS_DOMAIN_MSG_FIFO_CONTROL_GET_FLOW_CTRL_DISABLED: flow control disabled, space always available + * - otherwise: space is available when + * ((local_put + 1) % local_fifo_size_entries) != get + * 3. If out of space, then: + * - increment @c local_num_dropped_messages + * - write it to nvs_domain_msg_fifo_control::num_dropped_messages + * - do not proceed with this sequence + * - Notes: + * - scheduler --> client: nvs_domain_msg_fifo_control::num_dropped_messages + * indicates that messages were dropped. Logging an + * overflow event may be applicable. + * - client --> scheduler: The usermode client should return an error. + * 4. Read-write memory barrier + * 5. Write the message to nvs_domain_msg_fifo::messages[local_put] + * - NOTE: if the message size is less than the size of the array entry, it + * should be appended with 0 to fill the entry. This allows extending the + * messages with new fields in later protocol versions in a backwards + * compatible manner. + * - NOTE: this update does not need to be atomic + * 6. Write memory barrier + * 7. Increment @c local_put (modulo fifo size). In case of a wrap-around, + * increment also @c local_revolution_count + * 8. Write local_put | (local_revolution_count << 32) + * to nvs_domain_msg_fifo_control::put_revolutions. This write + * should be atomic 64-bit write. + * + * + * Receiving a message in the FIFO ring buffer (read-write access client) + * --------------------------------------------------------------- + * + * The receiver is suggested to maintain the following variables locally: + * - @c local_get --- local copy of get index + * - @c local_fifo_size_entries --- local copy of the FIFO ring buffer size + * + * When the reader is initialized, it should: + * + * 1. atomic read nvs_domain_msg_fifo_control::put_revolutions and store the + * 32-bit lower bits as @c local_get + * 2. store @c local_get to nvs_domain_msg_fifo_control::get. This enables + * flow control. + * + * When the reader exits, it should write + * #NVS_DOMAIN_MSG_FIFO_CONTROL_GET_FLOW_CTRL_DISABLED in + * nvs_domain_msg_fifo_control::get. This disables flow control. Further, + * nvgpu-rm should also write + * #NVS_DOMAIN_MSG_FIFO_CONTROL_GET_FLOW_CTRL_DISABLED in + * nvs_domain_msg_fifo_control::get when the R/W reader client exits. This + * is to ensure that abnormal client exit (e.g., process crash) disables flow + * control. + * + * The sequence for reading a message: + * + * 1. Atomic read the bottom 32 bits (or whole field) of + * nvs_domain_msg_fifo_control::put_revolutions as @c put + * 2. If local_get == put, there are no more messages. Exit this + * sequence. + * 3. Read memory barrier + * 4. Read the message from nvs_domain_msg_fifo::messages[local_get] + * (non-atomic read ok) + * 5. Read-write memory barrier + * 6. Increment local_get (mod FIFO size) + * 7. Atomic write nvs_domain_msg_fifo_control::get + * + * + * Receiving a message in the FIFO ring buffer (read-only access client) + * --------------------------------------------------------------- + * + * NOTE: The read-only reader client should not be used for + * safety-critical operation. It does not have flow control and it is subject to + * FIFO overruns. The read-only client is intended for diagnostics and tracing. + * + * The receiver is suggested to maintain the following variables locally: + * - @c local_get --- local copy of get index + * - @c local_revolutions --- local copy of FIFO revolutions + * - @c local_fifo_size_entries --- local copy of the FIFO ring buffer size + * + * When the reader is initialized, it should: + * + * 1. atomic read nvs_domain_msg_fifo_control::put_revolutions and store the + * lower 32 bits as @c local_get, and the upper 32 bits as @c + * local_revolutions + * + * The sequence for reading a message: + * + * 1. Atomic read nvs_domain_msg_fifo_control::put_revolutions as @c put and + * @c revolutions + * 2. Determine whether the reader is more than a full revolution behind the + * writer. One way to do this is to calculate the total number of messages + * read and written, and then calculate the cyclic difference of the + * totals. + * @code + * cycleSize = FIFO_entries * (1 << 32) ; num messages until 'revolutions' wraps around + * messagesRead = local_get + (local_revolutions * FIFO_entries) + * messagesWritten = put + (revolutions * FIFO_entries) + * unreadMessages = (messagesWritten - messagesRead) mod cycleSize + * @endcode + * In case unreadMessages > FIFO_entries, a FIFO overrun has + * occurred. Note that in this formulation, care must be taken to avoid + * integer overflows during computation. + * + * It is up to the implementation what to do on FIFO overflow. Possibly, + * report an error and reset local_revolutions = revolutions and + * local_get = @c put. + * 3. If local_get == put, the are no unread messages. Exit this + * sequence. + * 4. Read memory barrier + * 5. Read the message from nvs_domain_msg_fifo::messages[local_get] + * (non-atomic read ok) + * 6. Read memory barrier + * 7. Atomic read nvs_domain_msg_fifo_control::put_revolutions as @c put and + * @c revolutions + * 8. Perform the FIFO overrun check again as in step 2. In case overrun is + * detected, then the message read on step 5 may have been overwritten + * while reading. + * + * It is up to the implementation what to do on FIFO overflow. Possibly, + * report an error and reset local_revolutions = revolutions and + * local_get = @c put. + * 9. Increment local_get (mod FIFO_entries). If there is a wrap-around, + * increment @c local_revolutions. + * + * @since 1.0.0 + */ +struct nvs_domain_msg_fifo_control { + + /** + * @brief Get index (updated by the RW consumer) + * + * @remark Special value + * #NVS_DOMAIN_MSG_FIFO_CONTROL_GET_FLOW_CTRL_DISABLED means no flow + * control (scheduler --> client buffers only) + * + * @since 1.0.0 + */ + uint32_t get; + + /** + * @brief Padding to fill up 64B + */ + uint32_t reserved0[15]; + + /** + * @brief Message put index and revolution count (updated by the producer) + * + * This member consists of two fields: + * + * - The lower 32 bits is the put index + * - The upper 32 bits is the revolution count, i.e., how many times the + * put index has wrapped around + * + * For example, this field would be incremented as follows for a FIFO of size 5: + * + * - 0x0000'0000'0000'0000 (initial value) + * - 0x0000'0000'0000'0001 + * - 0x0000'0000'0000'0002 + * - 0x0000'0000'0000'0003 + * - 0x0000'0000'0000'0004 + * - 0x0000'0001'0000'0000 (wrap-around, revolution count incremented) + * - 0x0000'0001'0000'0001 + * + * The intention of the revolution count is to provide read-only + * observers a mechanism to detect dropped messages. + * + * @sa NVS_DOMAIN_MSG_FIFO_CONTROL_PUT_REVOLUTIONS_PUT_LSB + * @sa NVS_DOMAIN_MSG_FIFO_CONTROL_PUT_REVOLUTIONS_PUT_MSB + * @sa NVS_DOMAIN_MSG_FIFO_CONTROL_PUT_REVOLUTIONS_REVOLUTIONS_LSB + * @sa NVS_DOMAIN_MSG_FIFO_CONTROL_PUT_REVOLUTIONS_REVOLUTIONS_MSB + * + * @since 1.0.0 + */ + uint64_t put_revolutions; + + /** + * @brief Number of dropped messages due to overrun (updated by the + * producer) + * + * @since 1.0.0 + */ + uint64_t num_dropped_messages; // number of lost messages due to buffer overrun + + /** + * @brief Padding to fill up 64B + */ + uint32_t reserved1[12]; +}; + +#if (defined(__cplusplus) && (__cplusplus >= 201103L)) +/* Double-check that the example in the documentation is correct */ +static_assert( + sizeof(nvs_domain_msg_fifo_control) == 128U, + "Verify the documented substitution (1)"); +static_assert( + sizeof(nvs_domain_message) == 64U, + "Verify the documented substitution (2)"); +static_assert( + (65536U - sizeof(nvs_domain_msg_fifo_control)) / sizeof(nvs_domain_message) == 1022U, + "Verify the documented example"); +#endif + +/** + * @brief The general FIFO ring buffer format + * + * The following FIFO ring buffers are specified: + * + * - client --> scheduler control request messages + * - scheduler --> client control response messages + * + * The FIFO must be aligned by 64 bytes. + * + * @since 1.0.0 + */ +struct nvs_domain_msg_fifo { + + /** + * @brief Message ring buffer control + * + * @since 1.0.0 + */ + struct nvs_domain_msg_fifo_control control; + + /** + * @brief Message ring buffer data + * + * @since 1.0.0 + */ + struct nvs_domain_message messages[]; +}; + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif diff --git a/nvsched/include/nvs/nvs-control-messages.h b/nvsched/include/nvs/nvs-control-messages.h new file mode 100644 index 000000000..5d0705ea1 --- /dev/null +++ b/nvsched/include/nvs/nvs-control-messages.h @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2022 NVIDIA Corporation. All rights reserved. + * + * NVIDIA Corporation and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA Corporation is strictly prohibited. + */ + +#ifndef NVS_CONTROL_MESSAGES_H +#define NVS_CONTROL_MESSAGES_H + +/** + * @file + * @brief NVIDIA GPU domain scheduler asynchronous message definitions + */ + +#if defined(__cplusplus) +#include +#else +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * @brief Communication error + * + * @sa nvs_domain_msg_ctrl_error_resp + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_MSG_TYPE_CTRL_ERROR (0U) + +/** + * @brief Unknown/undefined error + * + * @sa nvs_domain_msg_ctrl_error_resp::error_code + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_MSG_CTRL_ERROR_UNKNOWN (0U) + +/** + * @brief Unhandled message + * + * The scheduler received a message that it does not know how to handle. + * + * @sa nvs_domain_msg_ctrl_error_resp::error_code + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_MSG_CTRL_ERROR_UNHANDLED_MESSAGE (1U) + +/** + * @brief Communication error + * + * This control message is sent as a response to an erroneous request. + * + * @sa NVS_DOMAIN_MSG_TYPE_CTRL_ERROR + * + * @since 1.0.0 + */ +struct nvs_domain_msg_ctrl_error_resp { + + /** + * @brief Communication error code + * + * See NVS_DOMAIN_MSG_CTRL_ERROR_* error codes. + * + * @since 1.0.0 + */ + uint32_t error_code; +}; + +/** + * @brief Scheduler capability query + * + * @sa nvs_domain_msg_ctrl_get_caps_req + * @sa nvs_domain_msg_ctrl_get_caps_resp + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_MSG_TYPE_CTRL_GET_CAPS_INFO (1U) + +/** + * @brief Scheduler capability query request + * + * The client version is used by the scheduler to check the client + * compatibility, following the semantic versioning specification. (See + * #NVS_DOMAIN_SCHED_VERSION_MAJOR for details.) + * + * @sa NVS_DOMAIN_MSG_TYPE_CTRL_GET_CAPS_INFO + * @sa nvs_domain_msg_ctrl_get_caps_resp::client_version_status + * + * + * @since 1.0.0 + */ +struct nvs_domain_msg_ctrl_get_caps_req { + + /** + * @brief Client major version + * + * @since 1.0.0 + */ + uint8_t client_version_major; + + /** + * @brief Client minor version + * + * @since 1.0.0 + */ + uint8_t client_version_minor; + + /** + * @brief Client patch level + * + * @since 1.0.0 + */ + uint8_t client_version_patch; +}; + +/** + * @brief Major version of the domain scheduler interface + * + * The versioning scheme follows the Semantic Versioning 2.0.0 + * specification. See https://semver.org/spec/v2.0.0.html + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_SCHED_VERSION_MAJOR (1U) + +/** + * @brief Minor version of the domain scheduler interface + * + * The versioning scheme follows the Semantic Versioning 2.0.0 + * specification. See https://semver.org/spec/v2.0.0.html + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_SCHED_VERSION_MINOR (0U) + +/** + * @brief Patch version of the domain scheduler interface + * + * The versioning scheme follows the Semantic Versioning 2.0.0 + * specification. See https://semver.org/spec/v2.0.0.html + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_SCHED_VERSION_PATCH (0U) + +/** + * @brief Client version check failed + * + * The client should not proceed with scheduler communication. The + * scheduler is not expected to be compatible. + */ +#define NVS_DOMAIN_MSG_CTRL_GET_CAPS_RESP_CLIENT_VERSION_STATUS_FAILED (0U) + +/** + * @brief Client version check passed + */ +#define NVS_DOMAIN_MSG_CTRL_GET_CAPS_RESP_CLIENT_VERSION_STATUS_OK (1U) + +/** + * @brief Scheduler capability query response + * + * @sa NVS_DOMAIN_MSG_TYPE_CTRL_GET_CAPS_INFO + * + * @since 1.0.0 + */ +struct nvs_domain_msg_ctrl_get_caps_resp { + + /** + * @brief Scheduler major version + * + * @since 1.0.0 + */ + uint8_t sched_version_major; + + /** + * @brief Scheduler minor version + * + * @since 1.0.0 + */ + uint8_t sched_version_minor; + + /** + * @brief Scheduler patch level + * + * @since 1.0.0 + */ + uint8_t sched_version_patch; + + /** + * @brief Client version check status + * + * This field indicates the scheduler-side check for client + * version compatibility. In general, the version numbering + * scheme follows the semantic versioning specification (see + * #NVS_DOMAIN_SCHED_VERSION_MAJOR). Additionally, the scheduler is + * allowed to fail this check for known incompatible or otherwise bad + * versions of the client. + * + * In general: + * - When the client and scheduler major version numbers match, + * #NVS_DOMAIN_MSG_CTRL_GET_CAPS_RESP_CLIENT_VERSION_STATUS_OK + * is returned. + * - When the client and scheduler major versions do not match, + * #NVS_DOMAIN_MSG_CTRL_GET_CAPS_RESP_CLIENT_VERSION_STATUS_FAILED + * is returned. Future note: If the client supports multiple + * scheduler major versions, the client is allowed to send + * #nvs_domain_msg_ctrl_get_caps_req again with a compatible + * version number. + * + * @since 1.0.0 + */ + uint8_t client_version_status; +}; + +/** + * @brief Switch to another domain + * + * @sa nvs_domain_msg_ctrl_switch_domain_req + * @sa nvs_domain_msg_ctrl_switch_domain_resp + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_MSG_TYPE_CTRL_SWITCH_DOMAIN (2U) + +/** + * @brief Pseudo-domain ID for all TSGs over all domains + * + * @sa nvs_domain_msg_ctrl_switch_domain_req::domain_id + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_CTRL_DOMAIN_ID_ALL (~(uint64_t)0U) + +/** + * @brief Scheduler domain switch request + * + * @sa NVS_DOMAIN_MSG_TYPE_CTRL_SWITCH_DOMAIN + * + * @since 1.0.0 + */ +struct nvs_domain_msg_ctrl_switch_domain_req { + + /** + * @brief Domain id + * + * @remark Domain id #NVS_DOMAIN_CTRL_DOMAIN_ID_ALL has a special meaning. This + * is a request to switch to a runlist that contains all TSGs in all domains. + * + * @since 1.0.0 + */ + uint64_t domain_id; +}; + +/** + * @brief Scheduler domain switch succeeded + * + * @sa nvs_domain_msg_ctrl_switch_domain_resp::status + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_MSG_TYPE_CTRL_SWITCH_DOMAIN_STATUS_SUCCESS (0U) + +/** + * @brief Scheduler domain switch response + * + * @sa NVS_DOMAIN_MSG_TYPE_CTRL_SWITCH_DOMAIN + * + * @since 1.0.0 + */ +struct nvs_domain_msg_ctrl_switch_domain_resp { + + /** + * @brief Domain switch status + * + * @remark The domain scheduler may return a status code that + * is not listed below. In this case, domain switch failed and + * the status code is returned for diagnostic and debugging + * purposes. + * + * @sa NVS_DOMAIN_MSG_TYPE_CTRL_SWITCH_DOMAIN_STATUS_SUCCESS + * + * @since 1.0.0 + */ + uint8_t status; + + /** + * @brief Padding to ensure 8B alignment for the next field + * for 32/64-bit compatibility + */ + uint8_t reserved[7]; + + /** + * @brief Time it took to preempt and switch to the new domain (nanoseconds) + * + * @since 1.0.0 + */ + uint64_t switch_ns; +}; + + +/** + * @brief Maximum payload size for #nvs_domain_message. + * + * @sa nvs_domain_message::payload + * + * @since 1.0.0 + */ +#define NVS_DOMAIN_MESSAGE_MAX_PAYLOAD_SIZE (48U) + + +/** + * @brief Payload union + * + * Union that contains all defined messages. + * + * @since 1.0.0 + */ +union nvs_domain_msg_payload_union { + /** + * @brief Control response message: communication error + * @since 1.0.0 + */ + struct nvs_domain_msg_ctrl_error_resp resp_error; + + /** + * @brief Control request message: get_caps + * @since 1.0.0 + */ + struct nvs_domain_msg_ctrl_get_caps_req req_get_caps; + + /** + * @brief Control response message: get_caps + * @since 1.0.0 + */ + struct nvs_domain_msg_ctrl_get_caps_resp resp_get_caps; + + /** + * @brief Control request message: switch_domain + * @since 1.0.0 + */ + struct nvs_domain_msg_ctrl_switch_domain_req req_switch_domain; + + /** + * @brief Control response message: switch_domain + * @since 1.0.0 + */ + struct nvs_domain_msg_ctrl_switch_domain_resp resp_switch_domain; + + + /** + * @brief Raw message data + * + * @since 1.0.0 + */ + uint8_t raw_data[NVS_DOMAIN_MESSAGE_MAX_PAYLOAD_SIZE]; +}; + +#if (defined(__cplusplus) && (__cplusplus >= 201103L)) +static_assert( + sizeof(nvs_domain_msg_payload_union) == NVS_DOMAIN_MESSAGE_MAX_PAYLOAD_SIZE, + "Check for expected payload size"); +#endif + +/** + * @brief The generic NVS domain message envelope + * + * @since 1.0.0 + */ +struct nvs_domain_message { + + /** + * @brief FIFO-specific message type + * + * Message type defines: + * - control messages: NVS_DOMAIN_MSG_TYPE_CTRL_* + * + * @since 1.0.0 + */ + uint32_t type; + + /** + * @brief Client-provided message tag + * + * - **Request-response messages.** The client provides a tag + * which the scheduler copies to the corresponding + * response. + * + * @remark It is recommended that the client uses a sequence + * to generate the tags for easier request/response tracing. + * + * @since 1.0.0 + */ + uint32_t sequence_tag; + + /** + * @brief Message timestamp (nanoseconds) + * + * client --> scheduler: host CPU time (CLOCK_MONOTONIC) + * + * scheduler --> client: scheduler local time + * + * @remark The timestamp field is primarily intended for + * message tracing purposes for allowing the reconstruction of + * the timeline of events. For operational purposes such as + * measuring the request/response round-trips as a health + * indicator, the usermode software should use local CPU + * host-side clock sampling, instead. The GSP clock is not + * guaranteed to use the same time domain with the host + * CPU. Further, drift may occur between the host CPU and GSP + * time domains. + * + * @since 1.0.0 + */ + uint64_t timestamp_ns; + + /** + * @brief Payload union + * + * @since 1.0.0 + */ + union nvs_domain_msg_payload_union payload; +}; + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif