2 * AMD Cryptographic Coprocessor (CCP) driver
4 * Copyright (C) 2017 Advanced Micro Devices, Inc.
6 * Author: Gary R Hook <gary.hook@amd.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/debugfs.h>
14 #include <linux/ccp.h>
19 #define OBUFP (obuf + oboff)
21 #define OBUFSPC (OBUFLEN - oboff)
22 #define OSCNPRINTF(fmt, ...) \
23 scnprintf(OBUFP, OBUFSPC, fmt, ## __VA_ARGS__)
27 #define RI_VERSION_NUM 0x0000003F
28 #define RI_AES_PRESENT 0x00000040
29 #define RI_3DES_PRESENT 0x00000080
30 #define RI_SHA_PRESENT 0x00000100
31 #define RI_RSA_PRESENT 0x00000200
32 #define RI_ECC_PRESENT 0x00000400
33 #define RI_ZDE_PRESENT 0x00000800
34 #define RI_ZCE_PRESENT 0x00001000
35 #define RI_TRNG_PRESENT 0x00002000
36 #define RI_ELFC_PRESENT 0x00004000
37 #define RI_ELFC_SHIFT 14
38 #define RI_NUM_VQM 0x00078000
39 #define RI_NVQM_SHIFT 15
40 #define RI_NVQM(r) (((r) * RI_NUM_VQM) >> RI_NVQM_SHIFT)
41 #define RI_LSB_ENTRIES 0x0FF80000
42 #define RI_NLSB_SHIFT 19
43 #define RI_NLSB(r) (((r) * RI_LSB_ENTRIES) >> RI_NLSB_SHIFT)
45 static ssize_t
ccp5_debugfs_info_read(struct file
*filp
, char __user
*ubuf
,
46 size_t count
, loff_t
*offp
)
48 struct ccp_device
*ccp
= filp
->private_data
;
49 unsigned int oboff
= 0;
57 obuf
= kmalloc(OBUFLEN
, GFP_KERNEL
);
61 oboff
+= OSCNPRINTF("Device name: %s\n", ccp
->name
);
62 oboff
+= OSCNPRINTF(" RNG name: %s\n", ccp
->rngname
);
63 oboff
+= OSCNPRINTF(" # Queues: %d\n", ccp
->cmd_q_count
);
64 oboff
+= OSCNPRINTF(" # Cmds: %d\n", ccp
->cmd_count
);
66 regval
= ioread32(ccp
->io_regs
+ CMD5_PSP_CCP_VERSION
);
67 oboff
+= OSCNPRINTF(" Version: %d\n", regval
& RI_VERSION_NUM
);
68 oboff
+= OSCNPRINTF(" Engines:");
69 if (regval
& RI_AES_PRESENT
)
70 oboff
+= OSCNPRINTF(" AES");
71 if (regval
& RI_3DES_PRESENT
)
72 oboff
+= OSCNPRINTF(" 3DES");
73 if (regval
& RI_SHA_PRESENT
)
74 oboff
+= OSCNPRINTF(" SHA");
75 if (regval
& RI_RSA_PRESENT
)
76 oboff
+= OSCNPRINTF(" RSA");
77 if (regval
& RI_ECC_PRESENT
)
78 oboff
+= OSCNPRINTF(" ECC");
79 if (regval
& RI_ZDE_PRESENT
)
80 oboff
+= OSCNPRINTF(" ZDE");
81 if (regval
& RI_ZCE_PRESENT
)
82 oboff
+= OSCNPRINTF(" ZCE");
83 if (regval
& RI_TRNG_PRESENT
)
84 oboff
+= OSCNPRINTF(" TRNG");
85 oboff
+= OSCNPRINTF("\n");
86 oboff
+= OSCNPRINTF(" Queues: %d\n",
87 (regval
& RI_NUM_VQM
) >> RI_NVQM_SHIFT
);
88 oboff
+= OSCNPRINTF("LSB Entries: %d\n",
89 (regval
& RI_LSB_ENTRIES
) >> RI_NLSB_SHIFT
);
91 ret
= simple_read_from_buffer(ubuf
, count
, offp
, obuf
, oboff
);
97 /* Return a formatted buffer containing the current
98 * statistics across all queues for a CCP.
100 static ssize_t
ccp5_debugfs_stats_read(struct file
*filp
, char __user
*ubuf
,
101 size_t count
, loff_t
*offp
)
103 struct ccp_device
*ccp
= filp
->private_data
;
104 unsigned long total_xts_aes_ops
= 0;
105 unsigned long total_3des_ops
= 0;
106 unsigned long total_aes_ops
= 0;
107 unsigned long total_sha_ops
= 0;
108 unsigned long total_rsa_ops
= 0;
109 unsigned long total_ecc_ops
= 0;
110 unsigned long total_pt_ops
= 0;
111 unsigned long total_ops
= 0;
112 unsigned int oboff
= 0;
117 for (i
= 0; i
< ccp
->cmd_q_count
; i
++) {
118 struct ccp_cmd_queue
*cmd_q
= &ccp
->cmd_q
[i
];
120 total_ops
+= cmd_q
->total_ops
;
121 total_aes_ops
+= cmd_q
->total_aes_ops
;
122 total_xts_aes_ops
+= cmd_q
->total_xts_aes_ops
;
123 total_3des_ops
+= cmd_q
->total_3des_ops
;
124 total_sha_ops
+= cmd_q
->total_sha_ops
;
125 total_rsa_ops
+= cmd_q
->total_rsa_ops
;
126 total_pt_ops
+= cmd_q
->total_pt_ops
;
127 total_ecc_ops
+= cmd_q
->total_ecc_ops
;
130 obuf
= kmalloc(OBUFLEN
, GFP_KERNEL
);
134 oboff
+= OSCNPRINTF("Total Interrupts Handled: %ld\n",
135 ccp
->total_interrupts
);
136 oboff
+= OSCNPRINTF(" Total Operations: %ld\n",
138 oboff
+= OSCNPRINTF(" AES: %ld\n",
140 oboff
+= OSCNPRINTF(" XTS AES: %ld\n",
142 oboff
+= OSCNPRINTF(" SHA: %ld\n",
144 oboff
+= OSCNPRINTF(" SHA: %ld\n",
146 oboff
+= OSCNPRINTF(" RSA: %ld\n",
148 oboff
+= OSCNPRINTF(" Pass-Thru: %ld\n",
150 oboff
+= OSCNPRINTF(" ECC: %ld\n",
153 ret
= simple_read_from_buffer(ubuf
, count
, offp
, obuf
, oboff
);
159 /* Reset the counters in a queue
161 static void ccp5_debugfs_reset_queue_stats(struct ccp_cmd_queue
*cmd_q
)
163 cmd_q
->total_ops
= 0L;
164 cmd_q
->total_aes_ops
= 0L;
165 cmd_q
->total_xts_aes_ops
= 0L;
166 cmd_q
->total_3des_ops
= 0L;
167 cmd_q
->total_sha_ops
= 0L;
168 cmd_q
->total_rsa_ops
= 0L;
169 cmd_q
->total_pt_ops
= 0L;
170 cmd_q
->total_ecc_ops
= 0L;
173 /* A value was written to the stats variable, which
174 * should be used to reset the queue counters across
177 static ssize_t
ccp5_debugfs_stats_write(struct file
*filp
,
178 const char __user
*ubuf
,
179 size_t count
, loff_t
*offp
)
181 struct ccp_device
*ccp
= filp
->private_data
;
184 for (i
= 0; i
< ccp
->cmd_q_count
; i
++)
185 ccp5_debugfs_reset_queue_stats(&ccp
->cmd_q
[i
]);
186 ccp
->total_interrupts
= 0L;
191 /* Return a formatted buffer containing the current information
194 static ssize_t
ccp5_debugfs_queue_read(struct file
*filp
, char __user
*ubuf
,
195 size_t count
, loff_t
*offp
)
197 struct ccp_cmd_queue
*cmd_q
= filp
->private_data
;
198 unsigned int oboff
= 0;
206 obuf
= kmalloc(OBUFLEN
, GFP_KERNEL
);
210 oboff
+= OSCNPRINTF(" Total Queue Operations: %ld\n",
212 oboff
+= OSCNPRINTF(" AES: %ld\n",
213 cmd_q
->total_aes_ops
);
214 oboff
+= OSCNPRINTF(" XTS AES: %ld\n",
215 cmd_q
->total_xts_aes_ops
);
216 oboff
+= OSCNPRINTF(" SHA: %ld\n",
217 cmd_q
->total_3des_ops
);
218 oboff
+= OSCNPRINTF(" SHA: %ld\n",
219 cmd_q
->total_sha_ops
);
220 oboff
+= OSCNPRINTF(" RSA: %ld\n",
221 cmd_q
->total_rsa_ops
);
222 oboff
+= OSCNPRINTF(" Pass-Thru: %ld\n",
223 cmd_q
->total_pt_ops
);
224 oboff
+= OSCNPRINTF(" ECC: %ld\n",
225 cmd_q
->total_ecc_ops
);
227 regval
= ioread32(cmd_q
->reg_int_enable
);
228 oboff
+= OSCNPRINTF(" Enabled Interrupts:");
229 if (regval
& INT_EMPTY_QUEUE
)
230 oboff
+= OSCNPRINTF(" EMPTY");
231 if (regval
& INT_QUEUE_STOPPED
)
232 oboff
+= OSCNPRINTF(" STOPPED");
233 if (regval
& INT_ERROR
)
234 oboff
+= OSCNPRINTF(" ERROR");
235 if (regval
& INT_COMPLETION
)
236 oboff
+= OSCNPRINTF(" COMPLETION");
237 oboff
+= OSCNPRINTF("\n");
239 ret
= simple_read_from_buffer(ubuf
, count
, offp
, obuf
, oboff
);
245 /* A value was written to the stats variable for a
246 * queue. Reset the queue counters to this value.
248 static ssize_t
ccp5_debugfs_queue_write(struct file
*filp
,
249 const char __user
*ubuf
,
250 size_t count
, loff_t
*offp
)
252 struct ccp_cmd_queue
*cmd_q
= filp
->private_data
;
254 ccp5_debugfs_reset_queue_stats(cmd_q
);
259 static const struct file_operations ccp_debugfs_info_ops
= {
260 .owner
= THIS_MODULE
,
262 .read
= ccp5_debugfs_info_read
,
266 static const struct file_operations ccp_debugfs_queue_ops
= {
267 .owner
= THIS_MODULE
,
269 .read
= ccp5_debugfs_queue_read
,
270 .write
= ccp5_debugfs_queue_write
,
273 static const struct file_operations ccp_debugfs_stats_ops
= {
274 .owner
= THIS_MODULE
,
276 .read
= ccp5_debugfs_stats_read
,
277 .write
= ccp5_debugfs_stats_write
,
280 static struct dentry
*ccp_debugfs_dir
;
281 static DEFINE_MUTEX(ccp_debugfs_lock
);
283 #define MAX_NAME_LEN 20
285 void ccp5_debugfs_setup(struct ccp_device
*ccp
)
287 struct ccp_cmd_queue
*cmd_q
;
288 char name
[MAX_NAME_LEN
+ 1];
289 struct dentry
*debugfs_info
;
290 struct dentry
*debugfs_stats
;
291 struct dentry
*debugfs_q_instance
;
292 struct dentry
*debugfs_q_stats
;
295 if (!debugfs_initialized())
298 mutex_lock(&ccp_debugfs_lock
);
299 if (!ccp_debugfs_dir
)
300 ccp_debugfs_dir
= debugfs_create_dir(KBUILD_MODNAME
, NULL
);
301 mutex_unlock(&ccp_debugfs_lock
);
302 if (!ccp_debugfs_dir
)
305 ccp
->debugfs_instance
= debugfs_create_dir(ccp
->name
, ccp_debugfs_dir
);
306 if (!ccp
->debugfs_instance
)
309 debugfs_info
= debugfs_create_file("info", 0400,
310 ccp
->debugfs_instance
, ccp
,
311 &ccp_debugfs_info_ops
);
315 debugfs_stats
= debugfs_create_file("stats", 0600,
316 ccp
->debugfs_instance
, ccp
,
317 &ccp_debugfs_stats_ops
);
321 for (i
= 0; i
< ccp
->cmd_q_count
; i
++) {
322 cmd_q
= &ccp
->cmd_q
[i
];
324 snprintf(name
, MAX_NAME_LEN
- 1, "q%d", cmd_q
->id
);
327 debugfs_create_dir(name
, ccp
->debugfs_instance
);
328 if (!debugfs_q_instance
)
332 debugfs_create_file("stats", 0600,
333 debugfs_q_instance
, cmd_q
,
334 &ccp_debugfs_queue_ops
);
335 if (!debugfs_q_stats
)
342 debugfs_remove_recursive(ccp
->debugfs_instance
);
345 void ccp5_debugfs_destroy(void)
347 debugfs_remove_recursive(ccp_debugfs_dir
);