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