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, ×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 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