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