libxcoder 5.8.0
Loading...
Searching...
No Matches
ni_host_ts.c
Go to the documentation of this file.
1/*******************************************************************************
2 *
3 * Copyright (C) 2022 NETINT Technologies
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18 * SOFTWARE.
19 *
20 ******************************************************************************/
21
22/*!*****************************************************************************
23 * \file ni_host_ts.c
24 *
25 * \brief Set Host timestamp
26 ******************************************************************************/
27
28#include <stdio.h>
29#include <stdint.h>
30#include <string.h>
31#include <time.h>
32#include <unistd.h>
33#include <dirent.h>
34#include <limits.h>
35#include <sys/utsname.h>
36
37#include "ni_host_ts.h"
38#include "ni_quadraprobe.h"
39#include "ni_nvme.h"
40#include "ni_defs.h"
41#include "ni_device_api.h"
42#include "ni_util.h"
43
44#if defined(__linux__)
45
46#define TS_DEBOUNCE_MS 2000ULL
47
48static uint64_t s_last_ts_ms = 0;
49
50static uint64_t get_epoch_ms(void)
51{
52 struct timespec ts;
53 if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
54 return 0;
55 return (uint64_t)ts.tv_sec * 1000ULL + (uint64_t)ts.tv_nsec / 1000000ULL;
56}
57
58/*!*****************************************************************************
59 * \brief Resolve the NVMe namespace block device from a sysfs PCI path.
60 *
61 * \param[in] sysfs_path PCI device sysfs directory.
62 * \param[out] blk_dev Output buffer for the /dev/nvmeXnY path.
63 * \param[in] blk_dev_sz Size of blk_dev buffer.
64 *
65 * \return 0 on success, -1 if not found.
66 ******************************************************************************/
67static int sysfs_to_blk_dev(const char *sysfs_path, char *blk_dev,
68 size_t blk_dev_sz)
69{
70 char nvme_dir[PATH_MAX];
71 int n = snprintf(nvme_dir, sizeof(nvme_dir), "%s/nvme", sysfs_path);
72 if (n < 0 || n >= (int)sizeof(nvme_dir))
73 return -1;
74
75 DIR *d = opendir(nvme_dir);
76 if (!d)
77 return -1;
78
79 char ctrl_name[64] = {0};
80 struct dirent *entry;
81 while ((entry = readdir(d))) // NOLINT(concurrency-mt-unsafe) - single-threaded
82 {
83 if (entry->d_name[0] == '.')
84 continue;
85 if (strncmp(entry->d_name, "nvme", 4) == 0)
86 {
87 int m = snprintf(ctrl_name, sizeof(ctrl_name), "%s", entry->d_name);
88 if (m >= 0 && m < (int)sizeof(ctrl_name))
89 break;
90 }
91 }
92 (void)closedir(d);
93
94 if (ctrl_name[0] == '\0')
95 return -1;
96
97 char ns_dir[PATH_MAX];
98 n = snprintf(ns_dir, sizeof(ns_dir), "%s/nvme/%s", sysfs_path, ctrl_name);
99 if (n < 0 || n >= (int)sizeof(ns_dir))
100 return -1;
101
102 d = opendir(ns_dir);
103 if (!d)
104 return -1;
105
106 int found = 0;
107 while ((entry = readdir(d))) // NOLINT(concurrency-mt-unsafe) - single-threaded
108 {
109 if (entry->d_name[0] == '.')
110 continue;
111 if (strncmp(entry->d_name, ctrl_name, strlen(ctrl_name)) == 0 &&
112 entry->d_name[strlen(ctrl_name)] == 'n')
113 {
114 int k = snprintf(blk_dev, blk_dev_sz, "/dev/%s", entry->d_name);
115 if (k >= 0 && k < (int)blk_dev_sz)
116 found = 1;
117 break;
118 }
119 }
120 (void)closedir(d);
121 return found ? 0 : -1;
122}
123
124/*!*****************************************************************************
125 * \brief Send a custom config-session IO write command to set the host
126 * timestamp on the Quadra firmware.
127 *
128 * Failures are silently ignored; timestamp setting is best-effort.
129 ******************************************************************************/
130static void send_set_features_timestamp(const char *blk_dev, uint64_t epoch_ms)
131{
132 ni_device_handle_t fd = ni_device_open2(blk_dev, NI_DEVICE_READ_WRITE);
133 if (fd == NI_INVALID_DEVICE_HANDLE)
134 return;
135
137 memset(&cap, 0, sizeof(cap));
138 if (ni_device_capability_query2(fd, &cap, false) != NI_RETCODE_SUCCESS)
139 {
141 "%s: skipping host timestamp on %s: capability query failed\n",
142 __func__, blk_dev);
143 ni_device_close(fd);
144 return;
145 }
146
149 "6tB") < 0)
150 {
152 "%s: skipping host timestamp on %s: FW API version needs to be >= 6tB\n",
153 __func__, blk_dev);
154 ni_device_close(fd);
155 return;
156 }
157
158 void *buf = NULL;
159 if (ni_posix_memalign(&buf, sysconf(_SC_PAGESIZE), NI_DATA_BUFFER_LEN))
160 {
162 "%s: failed to allocate aligned buffer for %s\n",
163 __func__, blk_dev);
164 ni_device_close(fd);
165 return;
166 }
167 memset(buf, 0, NI_DATA_BUFFER_LEN);
168 memcpy(buf, &epoch_ms, sizeof(epoch_ms));
169
170 uint32_t lba = CONFIG_SESSION_SetHostTime_W(0);
171 (void)ni_nvme_send_write_cmd(fd, NI_INVALID_EVENT_HANDLE, buf,
172 NI_DATA_BUFFER_LEN, lba);
173 ni_aligned_free(buf);
174 ni_device_close(fd);
175}
176
177static int get_kernel_version(void)
178{
179 struct utsname uts;
180 if (uname(&uts) != 0)
181 return 0;
182
183 int major = 0, minor = 0, patch = 0;
184 if (sscanf(uts.release, "%d.%d.%d", &major, &minor, &patch) != 3) // NOLINT(cert-err34-c) - return value checked
185 return 0;
186
187 return major * 10000 + minor * 100 + patch;
188}
189
190void ni_host_ts_set(void)
191{
192 uint64_t epoch_ms = get_epoch_ms();
193 if (epoch_ms == 0)
194 return;
195
196 if (s_last_ts_ms != 0 && (epoch_ms - s_last_ts_ms) < TS_DEBOUNCE_MS)
197 return;
198
199 s_last_ts_ms = epoch_ms;
200
201 time_t now = (time_t)(epoch_ms / 1000);
202 char datebuf[64];
203 struct tm tm_buf;
204
205 int kernel_ver = get_kernel_version();
206
207 if (kernel_ver >= 41400)
208 return;
209
210 if (localtime_r(&now, &tm_buf) &&
211 strftime(datebuf, sizeof(datebuf), "%c", &tm_buf) > 0)
212 ni_log(NI_LOG_DEBUG, "Setting the date to %s (%d)\n", datebuf, kernel_ver);
213
214 QuadraDevice *devs = NULL;
215 int ndev = quadra_device_find(&devs);
216 if (ndev <= 0)
217 {
218 free(devs);
219 return;
220 }
221
222 for (int i = 0; i < ndev; i++)
223 {
224 char blk_dev[PATH_MAX];
225 if (sysfs_to_blk_dev(devs[i].sysfs_path, blk_dev, sizeof(blk_dev)) != 0)
226 continue;
227
228 ni_log(NI_LOG_DEBUG, "Setting timestamp on %s\n", blk_dev);
229 send_set_features_timestamp(blk_dev, epoch_ms);
230 }
231
232 free(devs);
233}
234
235#endif /* __linux__ */
236
Common NETINT definitions used by all modules.
#define NI_XCODER_REVISION_API_MAJOR_VER_IDX
Definition ni_defs.h:99
@ NI_RETCODE_SUCCESS
Definition ni_defs.h:448
ni_retcode_t ni_device_capability_query2(ni_device_handle_t device_handle, ni_device_capability_t *p_cap, bool device_in_ctxt)
Query device and return device capability structure This function had replaced ni_device_capability_q...
void ni_device_close(ni_device_handle_t device_handle)
Close device and release resources.
ni_device_handle_t ni_device_open2(const char *p_dev, ni_device_mode_t mode)
Open device and return device device_handle if successful.
Public definitions for operating NETINT video processing devices for video processing.
@ NI_DEVICE_READ_WRITE
Set host timestamp on Quadra NVMe controllers.
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition ni_log.c:183
@ NI_LOG_DEBUG
Definition ni_log.h:64
@ NI_LOG_ERROR
Definition ni_log.h:62
int32_t ni_nvme_send_write_cmd(ni_device_handle_t handle, ni_event_handle_t event_handle, void *p_data, uint32_t data_len, uint32_t lba)
Compose a io write command.
Definition ni_nvme.c:661
Private definitions for interfacing with NETINT video processing devices over NVMe.
#define CONFIG_SESSION_SetHostTime_W(sid)
Definition ni_nvme.h:921
#define NI_DATA_BUFFER_LEN
Definition ni_nvme.h:627
Quadraprobe definitions.
int ni_posix_memalign(void **memptr, size_t alignment, size_t size)
Allocate aligned memory.
Definition ni_util.c:206
int ni_cmp_fw_api_ver(const char ver1[], const char ver2[])
Compare two 3 character strings containing a FW API version. Handle comparision when FW API version f...
Definition ni_util.c:4383
Utility definitions.
#define ni_aligned_free(p_memptr)
Definition ni_util.h:402
device capability type