xref: /freebsd/sys/dev/qat/qat_common/adf_gen4_timer.c (revision ba3c1f5972d7b90feb6e6da47905ff2757e0fe57)
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /* Copyright(c) 2007-2022 Intel Corporation */
3 /* $FreeBSD$ */
4 #include "adf_accel_devices.h"
5 #include "adf_heartbeat.h"
6 #include "adf_common_drv.h"
7 #include "icp_qat_fw_init_admin.h"
8 #include "adf_gen4_timer.h"
9 
10 #include "adf_dev_err.h"
11 
12 #define ADF_GEN4_INT_TIMER_VALUE_IN_MS 200
13 /* Interval within timer interrupt. Value in miliseconds. */
14 
15 #define ADF_GEN4_MAX_INT_TIMER_VALUE_IN_MS 0xFFFFFFFF
16 /* MAX Interval within timer interrupt. Value in miliseconds. */
17 
18 static u64
19 adf_get_next_timeout(u32 timeout_val)
20 {
21 	u64 timeout = msecs_to_jiffies(timeout_val);
22 
23 	return rounddown(jiffies + timeout, timeout);
24 }
25 
26 static void
27 adf_hb_irq_bh_handler(struct work_struct *work)
28 {
29 	struct icp_qat_fw_init_admin_req req = { 0 };
30 	struct icp_qat_fw_init_admin_resp resp = { 0 };
31 	struct adf_hb_timer_data *hb_timer_data =
32 	    container_of(work, struct adf_hb_timer_data, hb_int_timer_work);
33 	struct adf_accel_dev *accel_dev = hb_timer_data->accel_dev;
34 	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
35 	u32 ae_mask = hw_data->ae_mask;
36 
37 	if (!accel_dev->int_timer || !accel_dev->int_timer->enabled)
38 		goto end;
39 
40 	/* Update heartbeat count via init/admin cmd */
41 	if (!accel_dev->admin) {
42 		device_printf(GET_DEV(accel_dev),
43 			      "adf_admin is not available\n");
44 		goto end;
45 	}
46 
47 	req.cmd_id = ICP_QAT_FW_HEARTBEAT_SYNC;
48 	req.heartbeat_ticks = accel_dev->int_timer->int_cnt;
49 
50 	if (adf_send_admin(accel_dev, &req, &resp, ae_mask))
51 		device_printf(GET_DEV(accel_dev),
52 			      "Failed to update qat's HB count\n");
53 
54 end:
55 	kfree(hb_timer_data);
56 }
57 
58 static void
59 timer_handler(struct timer_list *tl)
60 {
61 	struct adf_int_timer *int_timer = from_timer(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
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
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