1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /* Copyright(c) 2007-2022 Intel Corporation */
3 /* $FreeBSD$ */
4 #include "adf_accel_devices.h"
5 #include "adf_common_drv.h"
6
7 #include <linux/delay.h>
8
9 #define MEASURE_CLOCK_RETRIES 10
10 #define MEASURE_CLOCK_DELTA_THRESHOLD 100
11 #define MEASURE_CLOCK_DELAY 10000
12 #define ME_CLK_DIVIDER 16
13
14 #define CLK_DBGFS_FILE "frequency"
15 #define HB_SYSCTL_ERR(RC) \
16 do { \
17 if (!RC) { \
18 device_printf(GET_DEV(accel_dev), \
19 "Memory allocation failed in \
20 adf_heartbeat_dbg_add\n"); \
21 return ENOMEM; \
22 } \
23 } while (0)
24
25 int
26 adf_clock_debugfs_add(struct adf_accel_dev *accel_dev)
27 {
28 struct adf_hw_device_data *hw_data = accel_dev->hw_device;
29
30 struct sysctl_ctx_list *qat_sysctl_ctx;
31 struct sysctl_oid *qat_sysctl_tree;
32 struct sysctl_oid *rc = 0;
33
34 qat_sysctl_ctx =
35 device_get_sysctl_ctx(accel_dev->accel_pci_dev.pci_dev);
36 qat_sysctl_tree =
37 device_get_sysctl_tree(accel_dev->accel_pci_dev.pci_dev);
38
39 rc = SYSCTL_ADD_UINT(qat_sysctl_ctx,
40 SYSCTL_CHILDREN(qat_sysctl_tree),
41 OID_AUTO,
42 CLK_DBGFS_FILE,
43 CTLFLAG_RD,
44 &hw_data->clock_frequency,
45 0,
46 "clock frequency");
47 HB_SYSCTL_ERR(rc);
48 return 0;
49 }
50
51 /**
52 * adf_dev_measure_clock() -- Measure the CPM clock frequency
53 * @accel_dev: Pointer to acceleration device.
54 * @frequency: Pointer to returned frequency in Hz.
55 *
56 * Return: 0 on success, error code otherwise.
57 */
58 static int
59 measure_clock(struct adf_accel_dev *accel_dev, u32 *frequency)
60 {
61 struct timespec ts1;
62 struct timespec ts2;
63 struct timespec ts3;
64 struct timespec ts4;
65 struct timespec delta;
66 u64 delta_us = 0;
67 u64 timestamp1 = 0;
68 u64 timestamp2 = 0;
69 u64 temp = 0;
70 int tries = 0;
71
72 if (!accel_dev || !frequency)
73 return EIO;
74 do {
75 nanotime(&ts1);
76 if (adf_get_fw_timestamp(accel_dev, ×tamp1)) {
77 device_printf(GET_DEV(accel_dev),
78 "Failed to get fw timestamp\n");
79 return EIO;
80 }
81 nanotime(&ts2);
82
83 delta = timespec_sub(ts2, ts1);
84 temp = delta.tv_nsec;
85 do_div(temp, NSEC_PER_USEC);
86
87 delta_us = delta.tv_sec * USEC_PER_SEC + temp;
88 } while (delta_us > MEASURE_CLOCK_DELTA_THRESHOLD &&
89 ++tries < MEASURE_CLOCK_RETRIES);
90
91 if (tries >= MEASURE_CLOCK_RETRIES) {
92 device_printf(GET_DEV(accel_dev),
93 "Excessive clock measure delay\n");
94 return EIO;
95 }
96
97 usleep_range(MEASURE_CLOCK_DELAY, MEASURE_CLOCK_DELAY * 2);
98 tries = 0;
99 do {
100 nanotime(&ts3);
101 if (adf_get_fw_timestamp(accel_dev, ×tamp2)) {
102 device_printf(GET_DEV(accel_dev),
103 "Failed to get fw timestamp\n");
104 return EIO;
105 }
106 nanotime(&ts4);
107
108 delta = timespec_sub(ts4, ts3);
109 temp = delta.tv_nsec;
110 do_div(temp, NSEC_PER_USEC);
111
112 delta_us = delta.tv_sec * USEC_PER_SEC + temp;
113 } while (delta_us > MEASURE_CLOCK_DELTA_THRESHOLD &&
114 ++tries < MEASURE_CLOCK_RETRIES);
115
116 if (tries >= MEASURE_CLOCK_RETRIES) {
117 device_printf(GET_DEV(accel_dev),
118 "Excessive clock measure delay\n");
119 return EIO;
120 }
121
122 delta = timespec_sub(ts3, ts1);
123 temp =
124 delta.tv_sec * NSEC_PER_SEC + delta.tv_nsec + (NSEC_PER_USEC / 2);
125 do_div(temp, NSEC_PER_USEC);
126 delta_us = temp;
127 /* Don't pretend that this gives better than 100KHz resolution */
128 temp = (timestamp2 - timestamp1) * ME_CLK_DIVIDER * 10 + (delta_us / 2);
129 do_div(temp, delta_us);
130 *frequency = temp * 100000;
131
132 return 0;
133 }
134
135 /**
136 * adf_dev_measure_clock() -- Measure the CPM clock frequency
137 * @accel_dev: Pointer to acceleration device.
138 * @frequency: Pointer to returned frequency in Hz.
139 * @min: Minimum expected frequency
140 * @max: Maximum expected frequency
141 *
142 * Return: 0 on success, error code otherwise.
143 */
144 int
145 adf_dev_measure_clock(struct adf_accel_dev *accel_dev,
146 u32 *frequency,
147 u32 min,
148 u32 max)
149 {
150 int ret;
151 u32 freq;
152
153 ret = measure_clock(accel_dev, &freq);
154 if (ret)
155 return ret;
156
157 if (freq < min) {
158 device_printf(GET_DEV(accel_dev),
159 "Slow clock %d MHz measured, assuming %d\n",
160 freq,
161 min);
162 freq = min;
163 } else if (freq > max) {
164 device_printf(GET_DEV(accel_dev),
165 "Fast clock %d MHz measured, assuming %d\n",
166 freq,
167 max);
168 freq = max;
169 }
170 *frequency = freq;
171 return 0;
172 }
173
174 static inline u64
175 timespec_to_ms(const struct timespec *ts)
176 {
177 return (uint64_t)(ts->tv_sec * (1000)) + (ts->tv_nsec / NSEC_PER_MSEC);
178 }
179
180 u64
181 adf_clock_get_current_time(void)
182 {
183 struct timespec ts;
184
185 getnanotime(&ts);
186 return timespec_to_ms(&ts);
187 }
Cache object: 4dd5c2c5b4620fc8109368e53879472f
|