xref: /freebsd/sys/dev/qat/qat_common/adf_clock.c (revision 06c3fb27)
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
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
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, &timestamp1)) {
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, &timestamp2)) {
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
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
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
180 adf_clock_get_current_time(void)
181 {
182 	struct timespec ts;
183 
184 	getnanotime(&ts);
185 	return timespec_to_ms(&ts);
186 }
187