1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2023 Intel Corporation */
3
4 #include <linux/debugfs.h>
5 #include <linux/errno.h>
6 #include <linux/export.h>
7 #include <linux/fs.h>
8 #include <linux/kernel.h>
9 #include <linux/kstrtox.h>
10 #include <linux/types.h>
11 #include "adf_admin.h"
12 #include "adf_cfg.h"
13 #include "adf_common_drv.h"
14 #include "adf_heartbeat.h"
15 #include "adf_heartbeat_dbgfs.h"
16
17 #define HB_OK 0
18 #define HB_ERROR -1
19 #define HB_STATUS_MAX_STRLEN 4
20 #define HB_STATS_MAX_STRLEN 16
21
adf_hb_stats_read(struct file * file,char __user * user_buffer,size_t count,loff_t * ppos)22 static ssize_t adf_hb_stats_read(struct file *file, char __user *user_buffer,
23 size_t count, loff_t *ppos)
24 {
25 char buf[HB_STATS_MAX_STRLEN];
26 unsigned int *value;
27 int len;
28
29 if (*ppos > 0)
30 return 0;
31
32 value = file->private_data;
33 len = scnprintf(buf, sizeof(buf), "%u\n", *value);
34
35 return simple_read_from_buffer(user_buffer, count, ppos, buf, len + 1);
36 }
37
38 static const struct file_operations adf_hb_stats_fops = {
39 .owner = THIS_MODULE,
40 .open = simple_open,
41 .read = adf_hb_stats_read,
42 };
43
adf_hb_status_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)44 static ssize_t adf_hb_status_read(struct file *file, char __user *user_buf,
45 size_t count, loff_t *ppos)
46 {
47 enum adf_device_heartbeat_status hb_status;
48 char ret_str[HB_STATUS_MAX_STRLEN];
49 struct adf_accel_dev *accel_dev;
50 int ret_code;
51 size_t len;
52
53 if (*ppos > 0)
54 return 0;
55
56 accel_dev = file->private_data;
57 ret_code = HB_OK;
58
59 adf_heartbeat_status(accel_dev, &hb_status);
60
61 if (hb_status != HB_DEV_ALIVE)
62 ret_code = HB_ERROR;
63
64 len = scnprintf(ret_str, sizeof(ret_str), "%d\n", ret_code);
65
66 return simple_read_from_buffer(user_buf, count, ppos, ret_str, len + 1);
67 }
68
69 static const struct file_operations adf_hb_status_fops = {
70 .owner = THIS_MODULE,
71 .open = simple_open,
72 .read = adf_hb_status_read,
73 };
74
adf_hb_cfg_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)75 static ssize_t adf_hb_cfg_read(struct file *file, char __user *user_buf,
76 size_t count, loff_t *ppos)
77 {
78 char timer_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES];
79 struct adf_accel_dev *accel_dev;
80 unsigned int timer_ms;
81 int len;
82
83 if (*ppos > 0)
84 return 0;
85
86 accel_dev = file->private_data;
87 timer_ms = accel_dev->heartbeat->hb_timer;
88 len = scnprintf(timer_str, sizeof(timer_str), "%u\n", timer_ms);
89
90 return simple_read_from_buffer(user_buf, count, ppos, timer_str,
91 len + 1);
92 }
93
adf_hb_cfg_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)94 static ssize_t adf_hb_cfg_write(struct file *file, const char __user *user_buf,
95 size_t count, loff_t *ppos)
96 {
97 char input_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { };
98 struct adf_accel_dev *accel_dev;
99 int ret, written_chars;
100 unsigned int timer_ms;
101 u32 ticks;
102
103 accel_dev = file->private_data;
104 timer_ms = ADF_CFG_HB_TIMER_DEFAULT_MS;
105
106 /* last byte left as string termination */
107 if (count > sizeof(input_str) - 1)
108 return -EINVAL;
109
110 written_chars = simple_write_to_buffer(input_str, sizeof(input_str) - 1,
111 ppos, user_buf, count);
112 if (written_chars > 0) {
113 ret = kstrtouint(input_str, 10, &timer_ms);
114 if (ret) {
115 dev_err(&GET_DEV(accel_dev),
116 "heartbeat_cfg: Invalid value\n");
117 return ret;
118 }
119
120 if (timer_ms < ADF_CFG_HB_TIMER_MIN_MS) {
121 dev_err(&GET_DEV(accel_dev),
122 "heartbeat_cfg: Invalid value\n");
123 return -EINVAL;
124 }
125
126 /*
127 * On 4xxx devices adf_timer is responsible for HB updates and
128 * its period is fixed to 200ms
129 */
130 if (accel_dev->timer)
131 timer_ms = ADF_CFG_HB_TIMER_MIN_MS;
132
133 ret = adf_heartbeat_save_cfg_param(accel_dev, timer_ms);
134 if (ret)
135 return ret;
136
137 ret = adf_heartbeat_ms_to_ticks(accel_dev, timer_ms, &ticks);
138 if (ret)
139 return ret;
140
141 ret = adf_send_admin_hb_timer(accel_dev, ticks);
142 if (ret)
143 return ret;
144
145 accel_dev->heartbeat->hb_timer = timer_ms;
146 }
147
148 return written_chars;
149 }
150
151 static const struct file_operations adf_hb_cfg_fops = {
152 .owner = THIS_MODULE,
153 .open = simple_open,
154 .read = adf_hb_cfg_read,
155 .write = adf_hb_cfg_write,
156 };
157
adf_hb_error_inject_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)158 static ssize_t adf_hb_error_inject_write(struct file *file,
159 const char __user *user_buf,
160 size_t count, loff_t *ppos)
161 {
162 struct adf_accel_dev *accel_dev = file->private_data;
163 char buf[3];
164 int ret;
165
166 /* last byte left as string termination */
167 if (*ppos != 0 || count != 2)
168 return -EINVAL;
169
170 if (copy_from_user(buf, user_buf, count))
171 return -EFAULT;
172 buf[count] = '\0';
173
174 if (buf[0] != '1')
175 return -EINVAL;
176
177 ret = adf_heartbeat_inject_error(accel_dev);
178 if (ret) {
179 dev_err(&GET_DEV(accel_dev),
180 "Heartbeat error injection failed with status %d\n",
181 ret);
182 return ret;
183 }
184
185 dev_info(&GET_DEV(accel_dev), "Heartbeat error injection enabled\n");
186
187 return count;
188 }
189
190 static const struct file_operations adf_hb_error_inject_fops = {
191 .owner = THIS_MODULE,
192 .open = simple_open,
193 .write = adf_hb_error_inject_write,
194 };
195
adf_heartbeat_dbgfs_add(struct adf_accel_dev * accel_dev)196 void adf_heartbeat_dbgfs_add(struct adf_accel_dev *accel_dev)
197 {
198 struct adf_heartbeat *hb = accel_dev->heartbeat;
199
200 if (!hb)
201 return;
202
203 hb->dbgfs.base_dir = debugfs_create_dir("heartbeat", accel_dev->debugfs_dir);
204 hb->dbgfs.status = debugfs_create_file("status", 0400, hb->dbgfs.base_dir,
205 accel_dev, &adf_hb_status_fops);
206 hb->dbgfs.sent = debugfs_create_file("queries_sent", 0400, hb->dbgfs.base_dir,
207 &hb->hb_sent_counter, &adf_hb_stats_fops);
208 hb->dbgfs.failed = debugfs_create_file("queries_failed", 0400, hb->dbgfs.base_dir,
209 &hb->hb_failed_counter, &adf_hb_stats_fops);
210 hb->dbgfs.cfg = debugfs_create_file("config", 0600, hb->dbgfs.base_dir,
211 accel_dev, &adf_hb_cfg_fops);
212
213 if (IS_ENABLED(CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION)) {
214 struct dentry *inject_error __maybe_unused;
215
216 inject_error = debugfs_create_file("inject_error", 0200,
217 hb->dbgfs.base_dir, accel_dev,
218 &adf_hb_error_inject_fops);
219 #ifdef CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION
220 hb->dbgfs.inject_error = inject_error;
221 #endif
222 }
223 }
224 EXPORT_SYMBOL_GPL(adf_heartbeat_dbgfs_add);
225
adf_heartbeat_dbgfs_rm(struct adf_accel_dev * accel_dev)226 void adf_heartbeat_dbgfs_rm(struct adf_accel_dev *accel_dev)
227 {
228 struct adf_heartbeat *hb = accel_dev->heartbeat;
229
230 if (!hb)
231 return;
232
233 debugfs_remove(hb->dbgfs.status);
234 hb->dbgfs.status = NULL;
235 debugfs_remove(hb->dbgfs.sent);
236 hb->dbgfs.sent = NULL;
237 debugfs_remove(hb->dbgfs.failed);
238 hb->dbgfs.failed = NULL;
239 debugfs_remove(hb->dbgfs.cfg);
240 hb->dbgfs.cfg = NULL;
241 #ifdef CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION
242 debugfs_remove(hb->dbgfs.inject_error);
243 hb->dbgfs.inject_error = NULL;
244 #endif
245 debugfs_remove(hb->dbgfs.base_dir);
246 hb->dbgfs.base_dir = NULL;
247 }
248 EXPORT_SYMBOL_GPL(adf_heartbeat_dbgfs_rm);
249