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_heartbeat_dbgfs_add(struct adf_accel_dev * accel_dev)158 void adf_heartbeat_dbgfs_add(struct adf_accel_dev *accel_dev)
159 {
160 struct adf_heartbeat *hb = accel_dev->heartbeat;
161
162 if (!hb)
163 return;
164
165 hb->dbgfs.base_dir = debugfs_create_dir("heartbeat", accel_dev->debugfs_dir);
166 hb->dbgfs.status = debugfs_create_file("status", 0400, hb->dbgfs.base_dir,
167 accel_dev, &adf_hb_status_fops);
168 hb->dbgfs.sent = debugfs_create_file("queries_sent", 0400, hb->dbgfs.base_dir,
169 &hb->hb_sent_counter, &adf_hb_stats_fops);
170 hb->dbgfs.failed = debugfs_create_file("queries_failed", 0400, hb->dbgfs.base_dir,
171 &hb->hb_failed_counter, &adf_hb_stats_fops);
172 hb->dbgfs.cfg = debugfs_create_file("config", 0600, hb->dbgfs.base_dir,
173 accel_dev, &adf_hb_cfg_fops);
174 }
175 EXPORT_SYMBOL_GPL(adf_heartbeat_dbgfs_add);
176
adf_heartbeat_dbgfs_rm(struct adf_accel_dev * accel_dev)177 void adf_heartbeat_dbgfs_rm(struct adf_accel_dev *accel_dev)
178 {
179 struct adf_heartbeat *hb = accel_dev->heartbeat;
180
181 if (!hb)
182 return;
183
184 debugfs_remove(hb->dbgfs.status);
185 hb->dbgfs.status = NULL;
186 debugfs_remove(hb->dbgfs.sent);
187 hb->dbgfs.sent = NULL;
188 debugfs_remove(hb->dbgfs.failed);
189 hb->dbgfs.failed = NULL;
190 debugfs_remove(hb->dbgfs.cfg);
191 hb->dbgfs.cfg = NULL;
192 debugfs_remove(hb->dbgfs.base_dir);
193 hb->dbgfs.base_dir = NULL;
194 }
195 EXPORT_SYMBOL_GPL(adf_heartbeat_dbgfs_rm);
196