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