1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AMD Cryptographic Coprocessor (CCP) driver 4 * 5 * Copyright (C) 2017 Advanced Micro Devices, Inc. 6 * 7 * Author: Gary R Hook <gary.hook@amd.com> 8 */ 9 10 #include <linux/debugfs.h> 11 #include <linux/ccp.h> 12 13 #include "ccp-dev.h" 14 15 /* DebugFS helpers */ 16 #define OBUFP (obuf + oboff) 17 #define OBUFLEN 512 18 #define OBUFSPC (OBUFLEN - oboff) 19 #define OSCNPRINTF(fmt, ...) \ 20 scnprintf(OBUFP, OBUFSPC, fmt, ## __VA_ARGS__) 21 22 #define BUFLEN 63 23 24 #define RI_VERSION_NUM 0x0000003F 25 #define RI_AES_PRESENT 0x00000040 26 #define RI_3DES_PRESENT 0x00000080 27 #define RI_SHA_PRESENT 0x00000100 28 #define RI_RSA_PRESENT 0x00000200 29 #define RI_ECC_PRESENT 0x00000400 30 #define RI_ZDE_PRESENT 0x00000800 31 #define RI_ZCE_PRESENT 0x00001000 32 #define RI_TRNG_PRESENT 0x00002000 33 #define RI_ELFC_PRESENT 0x00004000 34 #define RI_ELFC_SHIFT 14 35 #define RI_NUM_VQM 0x00078000 36 #define RI_NVQM_SHIFT 15 37 #define RI_NVQM(r) (((r) * RI_NUM_VQM) >> RI_NVQM_SHIFT) 38 #define RI_LSB_ENTRIES 0x0FF80000 39 #define RI_NLSB_SHIFT 19 40 #define RI_NLSB(r) (((r) * RI_LSB_ENTRIES) >> RI_NLSB_SHIFT) 41 42 static ssize_t ccp5_debugfs_info_read(struct file *filp, char __user *ubuf, 43 size_t count, loff_t *offp) 44 { 45 struct ccp_device *ccp = filp->private_data; 46 unsigned int oboff = 0; 47 unsigned int regval; 48 ssize_t ret; 49 char *obuf; 50 51 if (!ccp) 52 return 0; 53 54 obuf = kmalloc(OBUFLEN, GFP_KERNEL); 55 if (!obuf) 56 return -ENOMEM; 57 58 oboff += OSCNPRINTF("Device name: %s\n", ccp->name); 59 oboff += OSCNPRINTF(" RNG name: %s\n", ccp->rngname); 60 oboff += OSCNPRINTF(" # Queues: %d\n", ccp->cmd_q_count); 61 oboff += OSCNPRINTF(" # Cmds: %d\n", ccp->cmd_count); 62 63 regval = ioread32(ccp->io_regs + CMD5_PSP_CCP_VERSION); 64 oboff += OSCNPRINTF(" Version: %d\n", regval & RI_VERSION_NUM); 65 oboff += OSCNPRINTF(" Engines:"); 66 if (regval & RI_AES_PRESENT) 67 oboff += OSCNPRINTF(" AES"); 68 if (regval & RI_3DES_PRESENT) 69 oboff += OSCNPRINTF(" 3DES"); 70 if (regval & RI_SHA_PRESENT) 71 oboff += OSCNPRINTF(" SHA"); 72 if (regval & RI_RSA_PRESENT) 73 oboff += OSCNPRINTF(" RSA"); 74 if (regval & RI_ECC_PRESENT) 75 oboff += OSCNPRINTF(" ECC"); 76 if (regval & RI_ZDE_PRESENT) 77 oboff += OSCNPRINTF(" ZDE"); 78 if (regval & RI_ZCE_PRESENT) 79 oboff += OSCNPRINTF(" ZCE"); 80 if (regval & RI_TRNG_PRESENT) 81 oboff += OSCNPRINTF(" TRNG"); 82 oboff += OSCNPRINTF("\n"); 83 oboff += OSCNPRINTF(" Queues: %d\n", 84 (regval & RI_NUM_VQM) >> RI_NVQM_SHIFT); 85 oboff += OSCNPRINTF("LSB Entries: %d\n", 86 (regval & RI_LSB_ENTRIES) >> RI_NLSB_SHIFT); 87 88 ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff); 89 kfree(obuf); 90 91 return ret; 92 } 93 94 /* Return a formatted buffer containing the current 95 * statistics across all queues for a CCP. 96 */ 97 static ssize_t ccp5_debugfs_stats_read(struct file *filp, char __user *ubuf, 98 size_t count, loff_t *offp) 99 { 100 struct ccp_device *ccp = filp->private_data; 101 unsigned long total_xts_aes_ops = 0; 102 unsigned long total_3des_ops = 0; 103 unsigned long total_aes_ops = 0; 104 unsigned long total_sha_ops = 0; 105 unsigned long total_rsa_ops = 0; 106 unsigned long total_ecc_ops = 0; 107 unsigned long total_pt_ops = 0; 108 unsigned long total_ops = 0; 109 unsigned int oboff = 0; 110 ssize_t ret = 0; 111 unsigned int i; 112 char *obuf; 113 114 for (i = 0; i < ccp->cmd_q_count; i++) { 115 struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i]; 116 117 total_ops += cmd_q->total_ops; 118 total_aes_ops += cmd_q->total_aes_ops; 119 total_xts_aes_ops += cmd_q->total_xts_aes_ops; 120 total_3des_ops += cmd_q->total_3des_ops; 121 total_sha_ops += cmd_q->total_sha_ops; 122 total_rsa_ops += cmd_q->total_rsa_ops; 123 total_pt_ops += cmd_q->total_pt_ops; 124 total_ecc_ops += cmd_q->total_ecc_ops; 125 } 126 127 obuf = kmalloc(OBUFLEN, GFP_KERNEL); 128 if (!obuf) 129 return -ENOMEM; 130 131 oboff += OSCNPRINTF("Total Interrupts Handled: %ld\n", 132 ccp->total_interrupts); 133 oboff += OSCNPRINTF(" Total Operations: %ld\n", 134 total_ops); 135 oboff += OSCNPRINTF(" AES: %ld\n", 136 total_aes_ops); 137 oboff += OSCNPRINTF(" XTS AES: %ld\n", 138 total_xts_aes_ops); 139 oboff += OSCNPRINTF(" SHA: %ld\n", 140 total_3des_ops); 141 oboff += OSCNPRINTF(" SHA: %ld\n", 142 total_sha_ops); 143 oboff += OSCNPRINTF(" RSA: %ld\n", 144 total_rsa_ops); 145 oboff += OSCNPRINTF(" Pass-Thru: %ld\n", 146 total_pt_ops); 147 oboff += OSCNPRINTF(" ECC: %ld\n", 148 total_ecc_ops); 149 150 ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff); 151 kfree(obuf); 152 153 return ret; 154 } 155 156 /* Reset the counters in a queue 157 */ 158 static void ccp5_debugfs_reset_queue_stats(struct ccp_cmd_queue *cmd_q) 159 { 160 cmd_q->total_ops = 0L; 161 cmd_q->total_aes_ops = 0L; 162 cmd_q->total_xts_aes_ops = 0L; 163 cmd_q->total_3des_ops = 0L; 164 cmd_q->total_sha_ops = 0L; 165 cmd_q->total_rsa_ops = 0L; 166 cmd_q->total_pt_ops = 0L; 167 cmd_q->total_ecc_ops = 0L; 168 } 169 170 /* A value was written to the stats variable, which 171 * should be used to reset the queue counters across 172 * that device. 173 */ 174 static ssize_t ccp5_debugfs_stats_write(struct file *filp, 175 const char __user *ubuf, 176 size_t count, loff_t *offp) 177 { 178 struct ccp_device *ccp = filp->private_data; 179 int i; 180 181 for (i = 0; i < ccp->cmd_q_count; i++) 182 ccp5_debugfs_reset_queue_stats(&ccp->cmd_q[i]); 183 ccp->total_interrupts = 0L; 184 185 return count; 186 } 187 188 /* Return a formatted buffer containing the current information 189 * for that queue 190 */ 191 static ssize_t ccp5_debugfs_queue_read(struct file *filp, char __user *ubuf, 192 size_t count, loff_t *offp) 193 { 194 struct ccp_cmd_queue *cmd_q = filp->private_data; 195 unsigned int oboff = 0; 196 unsigned int regval; 197 ssize_t ret; 198 char *obuf; 199 200 if (!cmd_q) 201 return 0; 202 203 obuf = kmalloc(OBUFLEN, GFP_KERNEL); 204 if (!obuf) 205 return -ENOMEM; 206 207 oboff += OSCNPRINTF(" Total Queue Operations: %ld\n", 208 cmd_q->total_ops); 209 oboff += OSCNPRINTF(" AES: %ld\n", 210 cmd_q->total_aes_ops); 211 oboff += OSCNPRINTF(" XTS AES: %ld\n", 212 cmd_q->total_xts_aes_ops); 213 oboff += OSCNPRINTF(" SHA: %ld\n", 214 cmd_q->total_3des_ops); 215 oboff += OSCNPRINTF(" SHA: %ld\n", 216 cmd_q->total_sha_ops); 217 oboff += OSCNPRINTF(" RSA: %ld\n", 218 cmd_q->total_rsa_ops); 219 oboff += OSCNPRINTF(" Pass-Thru: %ld\n", 220 cmd_q->total_pt_ops); 221 oboff += OSCNPRINTF(" ECC: %ld\n", 222 cmd_q->total_ecc_ops); 223 224 regval = ioread32(cmd_q->reg_int_enable); 225 oboff += OSCNPRINTF(" Enabled Interrupts:"); 226 if (regval & INT_EMPTY_QUEUE) 227 oboff += OSCNPRINTF(" EMPTY"); 228 if (regval & INT_QUEUE_STOPPED) 229 oboff += OSCNPRINTF(" STOPPED"); 230 if (regval & INT_ERROR) 231 oboff += OSCNPRINTF(" ERROR"); 232 if (regval & INT_COMPLETION) 233 oboff += OSCNPRINTF(" COMPLETION"); 234 oboff += OSCNPRINTF("\n"); 235 236 ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff); 237 kfree(obuf); 238 239 return ret; 240 } 241 242 /* A value was written to the stats variable for a 243 * queue. Reset the queue counters to this value. 244 */ 245 static ssize_t ccp5_debugfs_queue_write(struct file *filp, 246 const char __user *ubuf, 247 size_t count, loff_t *offp) 248 { 249 struct ccp_cmd_queue *cmd_q = filp->private_data; 250 251 ccp5_debugfs_reset_queue_stats(cmd_q); 252 253 return count; 254 } 255 256 static const struct file_operations ccp_debugfs_info_ops = { 257 .owner = THIS_MODULE, 258 .open = simple_open, 259 .read = ccp5_debugfs_info_read, 260 .write = NULL, 261 }; 262 263 static const struct file_operations ccp_debugfs_queue_ops = { 264 .owner = THIS_MODULE, 265 .open = simple_open, 266 .read = ccp5_debugfs_queue_read, 267 .write = ccp5_debugfs_queue_write, 268 }; 269 270 static const struct file_operations ccp_debugfs_stats_ops = { 271 .owner = THIS_MODULE, 272 .open = simple_open, 273 .read = ccp5_debugfs_stats_read, 274 .write = ccp5_debugfs_stats_write, 275 }; 276 277 static struct dentry *ccp_debugfs_dir; 278 static DEFINE_MUTEX(ccp_debugfs_lock); 279 280 #define MAX_NAME_LEN 20 281 282 void ccp5_debugfs_setup(struct ccp_device *ccp) 283 { 284 struct ccp_cmd_queue *cmd_q; 285 char name[MAX_NAME_LEN + 1]; 286 struct dentry *debugfs_q_instance; 287 int i; 288 289 if (!debugfs_initialized()) 290 return; 291 292 mutex_lock(&ccp_debugfs_lock); 293 if (!ccp_debugfs_dir) 294 ccp_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); 295 mutex_unlock(&ccp_debugfs_lock); 296 297 ccp->debugfs_instance = debugfs_create_dir(ccp->name, ccp_debugfs_dir); 298 299 debugfs_create_file("info", 0400, ccp->debugfs_instance, ccp, 300 &ccp_debugfs_info_ops); 301 302 debugfs_create_file("stats", 0600, ccp->debugfs_instance, ccp, 303 &ccp_debugfs_stats_ops); 304 305 for (i = 0; i < ccp->cmd_q_count; i++) { 306 cmd_q = &ccp->cmd_q[i]; 307 308 snprintf(name, MAX_NAME_LEN - 1, "q%d", cmd_q->id); 309 310 debugfs_q_instance = 311 debugfs_create_dir(name, ccp->debugfs_instance); 312 313 debugfs_create_file("stats", 0600, debugfs_q_instance, cmd_q, 314 &ccp_debugfs_queue_ops); 315 } 316 317 return; 318 } 319 320 void ccp5_debugfs_destroy(void) 321 { 322 debugfs_remove_recursive(ccp_debugfs_dir); 323 } 324