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 } 188