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 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 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 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 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 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 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 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