xref: /freebsd/sys/dev/qat/qat_common/adf_clock.c (revision c7046f76c2c027b00c0e6ba57cfd28f1a78f5e23)
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, &timestamp1)) {
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, &timestamp2)) {
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 }
188