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