1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /* Copyright(c) 2007-2026 Intel Corporation */
3 #include "adf_accel_devices.h"
4 #include "adf_heartbeat.h"
5 #include "adf_common_drv.h"
6 #include "icp_qat_fw_init_admin.h"
7 #include "adf_gen4_timer.h"
8
9 #include "adf_dev_err.h"
10
11 #define ADF_GEN4_INT_TIMER_VALUE_IN_MS 200
12 /* Interval within timer interrupt. Value in miliseconds. */
13
14 #define ADF_GEN4_MAX_INT_TIMER_VALUE_IN_MS 0xFFFFFFFF
15 /* MAX Interval within timer interrupt. Value in miliseconds. */
16
17 static u64
adf_get_next_timeout(u32 timeout_val)18 adf_get_next_timeout(u32 timeout_val)
19 {
20 u64 timeout = msecs_to_jiffies(timeout_val);
21
22 return rounddown(jiffies + timeout, timeout);
23 }
24
25 static void
adf_hb_irq_bh_handler(struct work_struct * work)26 adf_hb_irq_bh_handler(struct work_struct *work)
27 {
28 struct icp_qat_fw_init_admin_req req = { 0 };
29 struct icp_qat_fw_init_admin_resp resp = { 0 };
30 struct adf_hb_timer_data *hb_timer_data =
31 container_of(work, struct adf_hb_timer_data, hb_int_timer_work);
32 struct adf_accel_dev *accel_dev = hb_timer_data->accel_dev;
33 struct adf_hw_device_data *hw_data = accel_dev->hw_device;
34 u64 ae_mask = hw_data->ae_mask;
35
36 if (!accel_dev->int_timer || !accel_dev->int_timer->enabled)
37 goto end;
38
39 /* Update heartbeat count via init/admin cmd */
40 if (!accel_dev->admin) {
41 device_printf(GET_DEV(accel_dev),
42 "adf_admin is not available\n");
43 goto end;
44 }
45
46 req.cmd_id = ICP_QAT_FW_HEARTBEAT_SYNC;
47 req.heartbeat_ticks = accel_dev->int_timer->int_cnt;
48
49 if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
50 device_printf(GET_DEV(accel_dev),
51 "Failed to update qat's HB count\n");
52
53 end:
54 kfree(hb_timer_data);
55 }
56
57 static void
timer_handler(struct timer_list * tl)58 timer_handler(struct timer_list *tl)
59 {
60 struct adf_int_timer *int_timer =
61 timer_container_of(int_timer, tl, timer);
62 struct adf_accel_dev *accel_dev = int_timer->accel_dev;
63 struct adf_hb_timer_data *hb_timer_data = NULL;
64 u64 timeout_val = adf_get_next_timeout(int_timer->timeout_val);
65 /* Update TL TBD */
66
67 /* Schedule a heartbeat work queue to update HB */
68 hb_timer_data = kzalloc(sizeof(*hb_timer_data), GFP_ATOMIC);
69 if (hb_timer_data) {
70 hb_timer_data->accel_dev = accel_dev;
71
72 INIT_WORK(&hb_timer_data->hb_int_timer_work,
73 adf_hb_irq_bh_handler);
74 queue_work(int_timer->timer_irq_wq,
75 &hb_timer_data->hb_int_timer_work);
76 } else {
77 device_printf(GET_DEV(accel_dev),
78 "Failed to alloc heartbeat timer data\n");
79 }
80 int_timer->int_cnt++;
81 mod_timer(tl, timeout_val);
82 }
83
84 int
adf_int_timer_init(struct adf_accel_dev * accel_dev)85 adf_int_timer_init(struct adf_accel_dev *accel_dev)
86 {
87 u64 timeout_val = adf_get_next_timeout(ADF_GEN4_INT_TIMER_VALUE_IN_MS);
88 struct adf_int_timer *int_timer = NULL;
89 char wqname[32] = { 0 };
90
91 if (!accel_dev)
92 return 0;
93
94 int_timer = kzalloc(sizeof(*int_timer), GFP_KERNEL);
95 if (!int_timer)
96 return -ENOMEM;
97
98 sprintf(wqname, "qat_timer_wq_%d", accel_dev->accel_id);
99
100 int_timer->timer_irq_wq = alloc_workqueue(wqname, WQ_MEM_RECLAIM, 1);
101
102 if (!int_timer->timer_irq_wq) {
103 kfree(int_timer);
104 return -ENOMEM;
105 }
106
107 int_timer->accel_dev = accel_dev;
108 int_timer->timeout_val = ADF_GEN4_INT_TIMER_VALUE_IN_MS;
109 int_timer->int_cnt = 0;
110 int_timer->enabled = true;
111 accel_dev->int_timer = int_timer;
112
113 timer_setup(&int_timer->timer, timer_handler, 0);
114 mod_timer(&int_timer->timer, timeout_val);
115
116 return 0;
117 }
118
119 void
adf_int_timer_exit(struct adf_accel_dev * accel_dev)120 adf_int_timer_exit(struct adf_accel_dev *accel_dev)
121 {
122 if (accel_dev && accel_dev->int_timer) {
123 del_timer_sync(&accel_dev->int_timer->timer);
124 accel_dev->int_timer->enabled = false;
125
126 if (accel_dev->int_timer->timer_irq_wq) {
127 flush_workqueue(accel_dev->int_timer->timer_irq_wq);
128 destroy_workqueue(accel_dev->int_timer->timer_irq_wq);
129 }
130
131 kfree(accel_dev->int_timer);
132 accel_dev->int_timer = NULL;
133 }
134 }
135