1 /* SPDX-License-Identifier: BSD-3-Clause */ 2 /* Copyright(c) 2007-2022 Intel Corporation */ 3 #include <sys/types.h> 4 #include <linux/random.h> 5 #include "qat_freebsd.h" 6 7 #include "adf_heartbeat.h" 8 #include "adf_common_drv.h" 9 #include "adf_cfg.h" 10 #include "adf_cfg_strings.h" 11 #include "icp_qat_fw_init_admin.h" 12 #include "adf_transport_internal.h" 13 14 #define MAX_HB_TICKS 0xFFFFFFFF 15 16 static int 17 adf_check_hb_poll_freq(struct adf_accel_dev *accel_dev) 18 { 19 u64 curr_hb_check_time = 0; 20 char timer_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 }; 21 unsigned int timer_val = ADF_CFG_HB_DEFAULT_VALUE; 22 23 curr_hb_check_time = adf_clock_get_current_time(); 24 25 if (!adf_cfg_get_param_value(accel_dev, 26 ADF_GENERAL_SEC, 27 ADF_HEARTBEAT_TIMER, 28 (char *)timer_str)) { 29 if (compat_strtouint((char *)timer_str, 30 ADF_CFG_BASE_DEC, 31 &timer_val)) 32 timer_val = ADF_CFG_HB_DEFAULT_VALUE; 33 } 34 if ((curr_hb_check_time - accel_dev->heartbeat->last_hb_check_time) < 35 timer_val) { 36 return EINVAL; 37 } 38 accel_dev->heartbeat->last_hb_check_time = curr_hb_check_time; 39 40 return 0; 41 } 42 43 int 44 adf_heartbeat_init(struct adf_accel_dev *accel_dev) 45 { 46 if (accel_dev->heartbeat) 47 adf_heartbeat_clean(accel_dev); 48 49 accel_dev->heartbeat = 50 malloc(sizeof(*accel_dev->heartbeat), M_QAT, M_WAITOK | M_ZERO); 51 52 return 0; 53 } 54 55 void 56 adf_heartbeat_clean(struct adf_accel_dev *accel_dev) 57 { 58 free(accel_dev->heartbeat, M_QAT); 59 accel_dev->heartbeat = NULL; 60 } 61 62 int 63 adf_get_hb_timer(struct adf_accel_dev *accel_dev, unsigned int *value) 64 { 65 struct adf_hw_device_data *hw_data = accel_dev->hw_device; 66 char timer_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 }; 67 unsigned int timer_val = ADF_CFG_HB_DEFAULT_VALUE; 68 u32 clk_per_sec = 0; 69 70 /* HB clock may be different than AE clock */ 71 if (hw_data->get_hb_clock) { 72 clk_per_sec = (u32)hw_data->get_hb_clock(hw_data); 73 } else if (hw_data->get_ae_clock) { 74 clk_per_sec = (u32)hw_data->get_ae_clock(hw_data); 75 } else { 76 return EINVAL; 77 } 78 79 /* Get Heartbeat Timer value from the configuration */ 80 if (!adf_cfg_get_param_value(accel_dev, 81 ADF_GENERAL_SEC, 82 ADF_HEARTBEAT_TIMER, 83 (char *)timer_str)) { 84 if (compat_strtouint((char *)timer_str, 85 ADF_CFG_BASE_DEC, 86 &timer_val)) 87 timer_val = ADF_CFG_HB_DEFAULT_VALUE; 88 } 89 90 if (timer_val < ADF_MIN_HB_TIMER_MS) { 91 device_printf(GET_DEV(accel_dev), 92 "%s value cannot be lesser than %u\n", 93 ADF_HEARTBEAT_TIMER, 94 ADF_MIN_HB_TIMER_MS); 95 return EINVAL; 96 } 97 98 /* Convert msec to clocks */ 99 clk_per_sec = clk_per_sec / 1000; 100 *value = timer_val * clk_per_sec; 101 102 return 0; 103 } 104 105 int 106 adf_get_heartbeat_status(struct adf_accel_dev *accel_dev) 107 { 108 struct icp_qat_fw_init_admin_hb_cnt *live_s, *last_s, *curr_s; 109 struct adf_hw_device_data *hw_device = accel_dev->hw_device; 110 const size_t max_aes = hw_device->get_num_aes(hw_device); 111 const size_t hb_ctrs = hw_device->heartbeat_ctr_num; 112 const size_t stats_size = 113 max_aes * hb_ctrs * sizeof(struct icp_qat_fw_init_admin_hb_cnt); 114 int ret = 0; 115 size_t ae, thr; 116 u16 *count_s; 117 unsigned long ae_mask = 0; 118 119 /* 120 * Memory layout of Heartbeat 121 * 122 * +----------------+----------------+---------+ 123 * | Live value | Last value | Count | 124 * +----------------+----------------+---------+ 125 * \_______________/\_______________/\________/ 126 * ^ ^ ^ 127 * | | | 128 * | | max_aes * hb_ctrs * 129 * | | sizeof(u16) 130 * | | 131 * | max_aes * hb_ctrs * 132 * | sizeof(icp_qat_fw_init_admin_hb_cnt) 133 * | 134 * max_aes * hb_ctrs * 135 * sizeof(icp_qat_fw_init_admin_hb_cnt) 136 */ 137 live_s = (struct icp_qat_fw_init_admin_hb_cnt *) 138 accel_dev->admin->virt_hb_addr; 139 last_s = live_s + (max_aes * hb_ctrs); 140 count_s = (u16 *)(last_s + (max_aes * hb_ctrs)); 141 142 curr_s = malloc(stats_size, M_QAT, M_WAITOK | M_ZERO); 143 144 memcpy(curr_s, live_s, stats_size); 145 ae_mask = hw_device->ae_mask; 146 147 for_each_set_bit(ae, &ae_mask, max_aes) 148 { 149 struct icp_qat_fw_init_admin_hb_cnt *curr = 150 curr_s + ae * hb_ctrs; 151 struct icp_qat_fw_init_admin_hb_cnt *prev = 152 last_s + ae * hb_ctrs; 153 u16 *count = count_s + ae * hb_ctrs; 154 155 for (thr = 0; thr < hb_ctrs; ++thr) { 156 u16 req = curr[thr].req_heartbeat_cnt; 157 u16 resp = curr[thr].resp_heartbeat_cnt; 158 u16 last = prev[thr].resp_heartbeat_cnt; 159 160 if ((thr == ADF_AE_ADMIN_THREAD || req != resp) && 161 resp == last) { 162 u16 retry = ++count[thr]; 163 164 if (retry >= ADF_CFG_HB_COUNT_THRESHOLD) 165 ret = EIO; 166 } else { 167 count[thr] = 0; 168 } 169 } 170 } 171 172 /* Copy current stats for the next iteration */ 173 memcpy(last_s, curr_s, stats_size); 174 free(curr_s, M_QAT); 175 176 return ret; 177 } 178 179 int 180 adf_heartbeat_status(struct adf_accel_dev *accel_dev, 181 enum adf_device_heartbeat_status *hb_status) 182 { 183 /* Heartbeat is not implemented in VFs at the moment so they do not 184 * set get_heartbeat_status. Also, in case the device is not up, 185 * unsupported should be returned */ 186 if (!accel_dev || !accel_dev->hw_device || 187 !accel_dev->hw_device->get_heartbeat_status || 188 !accel_dev->heartbeat) { 189 *hb_status = DEV_HB_UNSUPPORTED; 190 return 0; 191 } 192 193 if (!adf_dev_started(accel_dev) || 194 test_bit(ADF_STATUS_RESTARTING, &accel_dev->status)) { 195 *hb_status = DEV_HB_UNRESPONSIVE; 196 accel_dev->heartbeat->last_hb_status = DEV_HB_UNRESPONSIVE; 197 return 0; 198 } 199 200 if (adf_check_hb_poll_freq(accel_dev) == EINVAL) { 201 *hb_status = accel_dev->heartbeat->last_hb_status; 202 return 0; 203 } 204 205 accel_dev->heartbeat->hb_sent_counter++; 206 if (unlikely(accel_dev->hw_device->get_heartbeat_status(accel_dev))) { 207 device_printf(GET_DEV(accel_dev), 208 "ERROR: QAT is not responding.\n"); 209 *hb_status = DEV_HB_UNRESPONSIVE; 210 accel_dev->heartbeat->last_hb_status = DEV_HB_UNRESPONSIVE; 211 accel_dev->heartbeat->hb_failed_counter++; 212 return adf_notify_fatal_error(accel_dev); 213 } 214 215 *hb_status = DEV_HB_ALIVE; 216 accel_dev->heartbeat->last_hb_status = DEV_HB_ALIVE; 217 218 return 0; 219 } 220