xref: /freebsd/sys/dev/qat/qat_common/adf_heartbeat.c (revision 71625ec9ad2a9bc8c09784fbd23b759830e0ee5f)
178ee8d1cSJulian Grajkowski /* SPDX-License-Identifier: BSD-3-Clause */
278ee8d1cSJulian Grajkowski /* Copyright(c) 2007-2022 Intel Corporation */
378ee8d1cSJulian Grajkowski #include <sys/types.h>
478ee8d1cSJulian Grajkowski #include <linux/random.h>
578ee8d1cSJulian Grajkowski #include "qat_freebsd.h"
678ee8d1cSJulian Grajkowski 
778ee8d1cSJulian Grajkowski #include "adf_heartbeat.h"
878ee8d1cSJulian Grajkowski #include "adf_common_drv.h"
978ee8d1cSJulian Grajkowski #include "adf_cfg.h"
1078ee8d1cSJulian Grajkowski #include "adf_cfg_strings.h"
1178ee8d1cSJulian Grajkowski #include "icp_qat_fw_init_admin.h"
1278ee8d1cSJulian Grajkowski #include "adf_transport_internal.h"
1378ee8d1cSJulian Grajkowski 
1478ee8d1cSJulian Grajkowski #define MAX_HB_TICKS 0xFFFFFFFF
1578ee8d1cSJulian Grajkowski 
1678ee8d1cSJulian Grajkowski static int
adf_check_hb_poll_freq(struct adf_accel_dev * accel_dev)1778ee8d1cSJulian Grajkowski adf_check_hb_poll_freq(struct adf_accel_dev *accel_dev)
1878ee8d1cSJulian Grajkowski {
1978ee8d1cSJulian Grajkowski 	u64 curr_hb_check_time = 0;
2078ee8d1cSJulian Grajkowski 	char timer_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
2178ee8d1cSJulian Grajkowski 	unsigned int timer_val = ADF_CFG_HB_DEFAULT_VALUE;
2278ee8d1cSJulian Grajkowski 
2378ee8d1cSJulian Grajkowski 	curr_hb_check_time = adf_clock_get_current_time();
2478ee8d1cSJulian Grajkowski 
2578ee8d1cSJulian Grajkowski 	if (!adf_cfg_get_param_value(accel_dev,
2678ee8d1cSJulian Grajkowski 				     ADF_GENERAL_SEC,
2778ee8d1cSJulian Grajkowski 				     ADF_HEARTBEAT_TIMER,
2878ee8d1cSJulian Grajkowski 				     (char *)timer_str)) {
2978ee8d1cSJulian Grajkowski 		if (compat_strtouint((char *)timer_str,
3078ee8d1cSJulian Grajkowski 				     ADF_CFG_BASE_DEC,
3178ee8d1cSJulian Grajkowski 				     &timer_val))
3278ee8d1cSJulian Grajkowski 			timer_val = ADF_CFG_HB_DEFAULT_VALUE;
3378ee8d1cSJulian Grajkowski 	}
3478ee8d1cSJulian Grajkowski 	if ((curr_hb_check_time - accel_dev->heartbeat->last_hb_check_time) <
3578ee8d1cSJulian Grajkowski 	    timer_val) {
3678ee8d1cSJulian Grajkowski 		return EINVAL;
3778ee8d1cSJulian Grajkowski 	}
3878ee8d1cSJulian Grajkowski 	accel_dev->heartbeat->last_hb_check_time = curr_hb_check_time;
3978ee8d1cSJulian Grajkowski 
4078ee8d1cSJulian Grajkowski 	return 0;
4178ee8d1cSJulian Grajkowski }
4278ee8d1cSJulian Grajkowski 
4378ee8d1cSJulian Grajkowski int
adf_heartbeat_init(struct adf_accel_dev * accel_dev)4478ee8d1cSJulian Grajkowski adf_heartbeat_init(struct adf_accel_dev *accel_dev)
4578ee8d1cSJulian Grajkowski {
4678ee8d1cSJulian Grajkowski 	if (accel_dev->heartbeat)
4778ee8d1cSJulian Grajkowski 		adf_heartbeat_clean(accel_dev);
4878ee8d1cSJulian Grajkowski 
4978ee8d1cSJulian Grajkowski 	accel_dev->heartbeat =
5078ee8d1cSJulian Grajkowski 	    malloc(sizeof(*accel_dev->heartbeat), M_QAT, M_WAITOK | M_ZERO);
5178ee8d1cSJulian Grajkowski 
5278ee8d1cSJulian Grajkowski 	return 0;
5378ee8d1cSJulian Grajkowski }
5478ee8d1cSJulian Grajkowski 
5578ee8d1cSJulian Grajkowski void
adf_heartbeat_clean(struct adf_accel_dev * accel_dev)5678ee8d1cSJulian Grajkowski adf_heartbeat_clean(struct adf_accel_dev *accel_dev)
5778ee8d1cSJulian Grajkowski {
5878ee8d1cSJulian Grajkowski 	free(accel_dev->heartbeat, M_QAT);
5978ee8d1cSJulian Grajkowski 	accel_dev->heartbeat = NULL;
6078ee8d1cSJulian Grajkowski }
6178ee8d1cSJulian Grajkowski 
6278ee8d1cSJulian Grajkowski int
adf_get_hb_timer(struct adf_accel_dev * accel_dev,unsigned int * value)6378ee8d1cSJulian Grajkowski adf_get_hb_timer(struct adf_accel_dev *accel_dev, unsigned int *value)
6478ee8d1cSJulian Grajkowski {
6578ee8d1cSJulian Grajkowski 	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
6678ee8d1cSJulian Grajkowski 	char timer_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 };
6778ee8d1cSJulian Grajkowski 	unsigned int timer_val = ADF_CFG_HB_DEFAULT_VALUE;
6878ee8d1cSJulian Grajkowski 	u32 clk_per_sec = 0;
6978ee8d1cSJulian Grajkowski 
70*a977168cSMichal Gulbicki 	/* HB clock may be different than AE clock */
71*a977168cSMichal Gulbicki 	if (hw_data->get_hb_clock) {
72*a977168cSMichal Gulbicki 		clk_per_sec = (u32)hw_data->get_hb_clock(hw_data);
73*a977168cSMichal Gulbicki 	} else if (hw_data->get_ae_clock) {
7478ee8d1cSJulian Grajkowski 		clk_per_sec = (u32)hw_data->get_ae_clock(hw_data);
75*a977168cSMichal Gulbicki 	} else {
76*a977168cSMichal Gulbicki 		return EINVAL;
77*a977168cSMichal Gulbicki 	}
7878ee8d1cSJulian Grajkowski 
7978ee8d1cSJulian Grajkowski 	/* Get Heartbeat Timer value from the configuration */
8078ee8d1cSJulian Grajkowski 	if (!adf_cfg_get_param_value(accel_dev,
8178ee8d1cSJulian Grajkowski 				     ADF_GENERAL_SEC,
8278ee8d1cSJulian Grajkowski 				     ADF_HEARTBEAT_TIMER,
8378ee8d1cSJulian Grajkowski 				     (char *)timer_str)) {
8478ee8d1cSJulian Grajkowski 		if (compat_strtouint((char *)timer_str,
8578ee8d1cSJulian Grajkowski 				     ADF_CFG_BASE_DEC,
8678ee8d1cSJulian Grajkowski 				     &timer_val))
8778ee8d1cSJulian Grajkowski 			timer_val = ADF_CFG_HB_DEFAULT_VALUE;
8878ee8d1cSJulian Grajkowski 	}
8978ee8d1cSJulian Grajkowski 
9078ee8d1cSJulian Grajkowski 	if (timer_val < ADF_MIN_HB_TIMER_MS) {
9178ee8d1cSJulian Grajkowski 		device_printf(GET_DEV(accel_dev),
9278ee8d1cSJulian Grajkowski 			      "%s value cannot be lesser than %u\n",
9378ee8d1cSJulian Grajkowski 			      ADF_HEARTBEAT_TIMER,
9478ee8d1cSJulian Grajkowski 			      ADF_MIN_HB_TIMER_MS);
9578ee8d1cSJulian Grajkowski 		return EINVAL;
9678ee8d1cSJulian Grajkowski 	}
9778ee8d1cSJulian Grajkowski 
9878ee8d1cSJulian Grajkowski 	/* Convert msec to clocks */
9978ee8d1cSJulian Grajkowski 	clk_per_sec = clk_per_sec / 1000;
10078ee8d1cSJulian Grajkowski 	*value = timer_val * clk_per_sec;
10178ee8d1cSJulian Grajkowski 
10278ee8d1cSJulian Grajkowski 	return 0;
10378ee8d1cSJulian Grajkowski }
10478ee8d1cSJulian Grajkowski 
10578ee8d1cSJulian Grajkowski int
adf_get_heartbeat_status(struct adf_accel_dev * accel_dev)10678ee8d1cSJulian Grajkowski adf_get_heartbeat_status(struct adf_accel_dev *accel_dev)
10778ee8d1cSJulian Grajkowski {
108*a977168cSMichal Gulbicki 	struct icp_qat_fw_init_admin_hb_cnt *live_s, *last_s, *curr_s;
10978ee8d1cSJulian Grajkowski 	struct adf_hw_device_data *hw_device = accel_dev->hw_device;
11078ee8d1cSJulian Grajkowski 	const size_t max_aes = hw_device->get_num_aes(hw_device);
111*a977168cSMichal Gulbicki 	const size_t hb_ctrs = hw_device->heartbeat_ctr_num;
11278ee8d1cSJulian Grajkowski 	const size_t stats_size =
113*a977168cSMichal Gulbicki 	    max_aes * hb_ctrs * sizeof(struct icp_qat_fw_init_admin_hb_cnt);
11478ee8d1cSJulian Grajkowski 	int ret = 0;
11578ee8d1cSJulian Grajkowski 	size_t ae, thr;
116*a977168cSMichal Gulbicki 	u16 *count_s;
11778ee8d1cSJulian Grajkowski 	unsigned long ae_mask = 0;
11878ee8d1cSJulian Grajkowski 
11978ee8d1cSJulian Grajkowski 	/*
12078ee8d1cSJulian Grajkowski 	 * Memory layout of Heartbeat
12178ee8d1cSJulian Grajkowski 	 *
12278ee8d1cSJulian Grajkowski 	 * +----------------+----------------+---------+
12378ee8d1cSJulian Grajkowski 	 * |   Live value   |   Last value   |  Count  |
12478ee8d1cSJulian Grajkowski 	 * +----------------+----------------+---------+
12578ee8d1cSJulian Grajkowski 	 * \_______________/\_______________/\________/
12678ee8d1cSJulian Grajkowski 	 *         ^                ^            ^
12778ee8d1cSJulian Grajkowski 	 *         |                |            |
128*a977168cSMichal Gulbicki 	 *         |                |            max_aes * hb_ctrs *
129*a977168cSMichal Gulbicki 	 *         |                |            sizeof(u16)
130*a977168cSMichal Gulbicki 	 *         |                |
131*a977168cSMichal Gulbicki 	 *         |                max_aes * hb_ctrs *
132*a977168cSMichal Gulbicki 	 *         |                sizeof(icp_qat_fw_init_admin_hb_cnt)
133*a977168cSMichal Gulbicki 	 *         |
134*a977168cSMichal Gulbicki 	 *         max_aes * hb_ctrs *
135*a977168cSMichal Gulbicki 	 *         sizeof(icp_qat_fw_init_admin_hb_cnt)
13678ee8d1cSJulian Grajkowski 	 */
137*a977168cSMichal Gulbicki 	live_s = (struct icp_qat_fw_init_admin_hb_cnt *)
138*a977168cSMichal Gulbicki 		     accel_dev->admin->virt_hb_addr;
139*a977168cSMichal Gulbicki 	last_s = live_s + (max_aes * hb_ctrs);
140*a977168cSMichal Gulbicki 	count_s = (u16 *)(last_s + (max_aes * hb_ctrs));
14178ee8d1cSJulian Grajkowski 
14278ee8d1cSJulian Grajkowski 	curr_s = malloc(stats_size, M_QAT, M_WAITOK | M_ZERO);
14378ee8d1cSJulian Grajkowski 
14478ee8d1cSJulian Grajkowski 	memcpy(curr_s, live_s, stats_size);
14578ee8d1cSJulian Grajkowski 	ae_mask = hw_device->ae_mask;
14678ee8d1cSJulian Grajkowski 
14778ee8d1cSJulian Grajkowski 	for_each_set_bit(ae, &ae_mask, max_aes)
14878ee8d1cSJulian Grajkowski 	{
14978ee8d1cSJulian Grajkowski 		struct icp_qat_fw_init_admin_hb_cnt *curr =
150*a977168cSMichal Gulbicki 		    curr_s + ae * hb_ctrs;
15178ee8d1cSJulian Grajkowski 		struct icp_qat_fw_init_admin_hb_cnt *prev =
152*a977168cSMichal Gulbicki 		    last_s + ae * hb_ctrs;
153*a977168cSMichal Gulbicki 		u16 *count = count_s + ae * hb_ctrs;
154*a977168cSMichal Gulbicki 
155*a977168cSMichal Gulbicki 		for (thr = 0; thr < hb_ctrs; ++thr) {
156*a977168cSMichal Gulbicki 			u16 req = curr[thr].req_heartbeat_cnt;
157*a977168cSMichal Gulbicki 			u16 resp = curr[thr].resp_heartbeat_cnt;
158*a977168cSMichal Gulbicki 			u16 last = prev[thr].resp_heartbeat_cnt;
15978ee8d1cSJulian Grajkowski 
16078ee8d1cSJulian Grajkowski 			if ((thr == ADF_AE_ADMIN_THREAD || req != resp) &&
16178ee8d1cSJulian Grajkowski 			    resp == last) {
162*a977168cSMichal Gulbicki 				u16 retry = ++count[thr];
16378ee8d1cSJulian Grajkowski 
16478ee8d1cSJulian Grajkowski 				if (retry >= ADF_CFG_HB_COUNT_THRESHOLD)
16578ee8d1cSJulian Grajkowski 					ret = EIO;
16678ee8d1cSJulian Grajkowski 			} else {
167*a977168cSMichal Gulbicki 				count[thr] = 0;
16878ee8d1cSJulian Grajkowski 			}
16978ee8d1cSJulian Grajkowski 		}
17078ee8d1cSJulian Grajkowski 	}
17178ee8d1cSJulian Grajkowski 
17278ee8d1cSJulian Grajkowski 	/* Copy current stats for the next iteration */
17378ee8d1cSJulian Grajkowski 	memcpy(last_s, curr_s, stats_size);
17478ee8d1cSJulian Grajkowski 	free(curr_s, M_QAT);
17578ee8d1cSJulian Grajkowski 
17678ee8d1cSJulian Grajkowski 	return ret;
17778ee8d1cSJulian Grajkowski }
17878ee8d1cSJulian Grajkowski 
17978ee8d1cSJulian Grajkowski int
adf_heartbeat_status(struct adf_accel_dev * accel_dev,enum adf_device_heartbeat_status * hb_status)18078ee8d1cSJulian Grajkowski adf_heartbeat_status(struct adf_accel_dev *accel_dev,
18178ee8d1cSJulian Grajkowski 		     enum adf_device_heartbeat_status *hb_status)
18278ee8d1cSJulian Grajkowski {
18378ee8d1cSJulian Grajkowski 	/* Heartbeat is not implemented in VFs at the moment so they do not
18478ee8d1cSJulian Grajkowski 	 * set get_heartbeat_status. Also, in case the device is not up,
18578ee8d1cSJulian Grajkowski 	 * unsupported should be returned */
18678ee8d1cSJulian Grajkowski 	if (!accel_dev || !accel_dev->hw_device ||
18778ee8d1cSJulian Grajkowski 	    !accel_dev->hw_device->get_heartbeat_status ||
18878ee8d1cSJulian Grajkowski 	    !accel_dev->heartbeat) {
18978ee8d1cSJulian Grajkowski 		*hb_status = DEV_HB_UNSUPPORTED;
19078ee8d1cSJulian Grajkowski 		return 0;
19178ee8d1cSJulian Grajkowski 	}
19278ee8d1cSJulian Grajkowski 
19378ee8d1cSJulian Grajkowski 	if (!adf_dev_started(accel_dev) ||
19478ee8d1cSJulian Grajkowski 	    test_bit(ADF_STATUS_RESTARTING, &accel_dev->status)) {
19578ee8d1cSJulian Grajkowski 		*hb_status = DEV_HB_UNRESPONSIVE;
19678ee8d1cSJulian Grajkowski 		accel_dev->heartbeat->last_hb_status = DEV_HB_UNRESPONSIVE;
19778ee8d1cSJulian Grajkowski 		return 0;
19878ee8d1cSJulian Grajkowski 	}
19978ee8d1cSJulian Grajkowski 
20078ee8d1cSJulian Grajkowski 	if (adf_check_hb_poll_freq(accel_dev) == EINVAL) {
20178ee8d1cSJulian Grajkowski 		*hb_status = accel_dev->heartbeat->last_hb_status;
20278ee8d1cSJulian Grajkowski 		return 0;
20378ee8d1cSJulian Grajkowski 	}
20478ee8d1cSJulian Grajkowski 
20578ee8d1cSJulian Grajkowski 	accel_dev->heartbeat->hb_sent_counter++;
20678ee8d1cSJulian Grajkowski 	if (unlikely(accel_dev->hw_device->get_heartbeat_status(accel_dev))) {
20778ee8d1cSJulian Grajkowski 		device_printf(GET_DEV(accel_dev),
20878ee8d1cSJulian Grajkowski 			      "ERROR: QAT is not responding.\n");
20978ee8d1cSJulian Grajkowski 		*hb_status = DEV_HB_UNRESPONSIVE;
21078ee8d1cSJulian Grajkowski 		accel_dev->heartbeat->last_hb_status = DEV_HB_UNRESPONSIVE;
21178ee8d1cSJulian Grajkowski 		accel_dev->heartbeat->hb_failed_counter++;
21278ee8d1cSJulian Grajkowski 		return adf_notify_fatal_error(accel_dev);
21378ee8d1cSJulian Grajkowski 	}
21478ee8d1cSJulian Grajkowski 
21578ee8d1cSJulian Grajkowski 	*hb_status = DEV_HB_ALIVE;
21678ee8d1cSJulian Grajkowski 	accel_dev->heartbeat->last_hb_status = DEV_HB_ALIVE;
21778ee8d1cSJulian Grajkowski 
21878ee8d1cSJulian Grajkowski 	return 0;
21978ee8d1cSJulian Grajkowski }
220