1 // SPDX-License-Identifier: GPL-2.0-only
3 * AMD Cryptographic Coprocessor (CCP) driver
5 * Copyright (C) 2017 Advanced Micro Devices, Inc.
7 * Author: Gary R Hook <gary.hook@amd.com>
10 #include <linux/debugfs.h>
11 #include <linux/ccp.h>
16 #define OBUFP (obuf + oboff)
18 #define OBUFSPC (OBUFLEN - oboff)
19 #define OSCNPRINTF(fmt, ...) \
20 scnprintf(OBUFP, OBUFSPC, fmt, ## __VA_ARGS__)
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)
42 static ssize_t
ccp5_debugfs_info_read(struct file
*filp
, char __user
*ubuf
,
43 size_t count
, loff_t
*offp
)
45 struct ccp_device
*ccp
= filp
->private_data
;
46 unsigned int oboff
= 0;
54 obuf
= kmalloc(OBUFLEN
, GFP_KERNEL
);
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
);
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
);
88 ret
= simple_read_from_buffer(ubuf
, count
, offp
, obuf
, oboff
);
94 /* Return a formatted buffer containing the current
95 * statistics across all queues for a CCP.
97 static ssize_t
ccp5_debugfs_stats_read(struct file
*filp
, char __user
*ubuf
,
98 size_t count
, loff_t
*offp
)
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;
114 for (i
= 0; i
< ccp
->cmd_q_count
; i
++) {
115 struct ccp_cmd_queue
*cmd_q
= &ccp
->cmd_q
[i
];
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
;
127 obuf
= kmalloc(OBUFLEN
, GFP_KERNEL
);
131 oboff
+= OSCNPRINTF("Total Interrupts Handled: %ld\n",
132 ccp
->total_interrupts
);
133 oboff
+= OSCNPRINTF(" Total Operations: %ld\n",
135 oboff
+= OSCNPRINTF(" AES: %ld\n",
137 oboff
+= OSCNPRINTF(" XTS AES: %ld\n",
139 oboff
+= OSCNPRINTF(" SHA: %ld\n",
141 oboff
+= OSCNPRINTF(" SHA: %ld\n",
143 oboff
+= OSCNPRINTF(" RSA: %ld\n",
145 oboff
+= OSCNPRINTF(" Pass-Thru: %ld\n",
147 oboff
+= OSCNPRINTF(" ECC: %ld\n",
150 ret
= simple_read_from_buffer(ubuf
, count
, offp
, obuf
, oboff
);
156 /* Reset the counters in a queue
158 static void ccp5_debugfs_reset_queue_stats(struct ccp_cmd_queue
*cmd_q
)
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;
170 /* A value was written to the stats variable, which
171 * should be used to reset the queue counters across
174 static ssize_t
ccp5_debugfs_stats_write(struct file
*filp
,
175 const char __user
*ubuf
,
176 size_t count
, loff_t
*offp
)
178 struct ccp_device
*ccp
= filp
->private_data
;
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;
188 /* Return a formatted buffer containing the current information
191 static ssize_t
ccp5_debugfs_queue_read(struct file
*filp
, char __user
*ubuf
,
192 size_t count
, loff_t
*offp
)
194 struct ccp_cmd_queue
*cmd_q
= filp
->private_data
;
195 unsigned int oboff
= 0;
203 obuf
= kmalloc(OBUFLEN
, GFP_KERNEL
);
207 oboff
+= OSCNPRINTF(" Total Queue Operations: %ld\n",
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
);
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");
236 ret
= simple_read_from_buffer(ubuf
, count
, offp
, obuf
, oboff
);
242 /* A value was written to the stats variable for a
243 * queue. Reset the queue counters to this value.
245 static ssize_t
ccp5_debugfs_queue_write(struct file
*filp
,
246 const char __user
*ubuf
,
247 size_t count
, loff_t
*offp
)
249 struct ccp_cmd_queue
*cmd_q
= filp
->private_data
;
251 ccp5_debugfs_reset_queue_stats(cmd_q
);
256 static const struct file_operations ccp_debugfs_info_ops
= {
257 .owner
= THIS_MODULE
,
259 .read
= ccp5_debugfs_info_read
,
263 static const struct file_operations ccp_debugfs_queue_ops
= {
264 .owner
= THIS_MODULE
,
266 .read
= ccp5_debugfs_queue_read
,
267 .write
= ccp5_debugfs_queue_write
,
270 static const struct file_operations ccp_debugfs_stats_ops
= {
271 .owner
= THIS_MODULE
,
273 .read
= ccp5_debugfs_stats_read
,
274 .write
= ccp5_debugfs_stats_write
,
277 static struct dentry
*ccp_debugfs_dir
;
278 static DEFINE_MUTEX(ccp_debugfs_lock
);
280 #define MAX_NAME_LEN 20
282 void ccp5_debugfs_setup(struct ccp_device
*ccp
)
284 struct ccp_cmd_queue
*cmd_q
;
285 char name
[MAX_NAME_LEN
+ 1];
286 struct dentry
*debugfs_q_instance
;
289 if (!debugfs_initialized())
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
);
297 ccp
->debugfs_instance
= debugfs_create_dir(ccp
->name
, ccp_debugfs_dir
);
299 debugfs_create_file("info", 0400, ccp
->debugfs_instance
, ccp
,
300 &ccp_debugfs_info_ops
);
302 debugfs_create_file("stats", 0600, ccp
->debugfs_instance
, ccp
,
303 &ccp_debugfs_stats_ops
);
305 for (i
= 0; i
< ccp
->cmd_q_count
; i
++) {
306 cmd_q
= &ccp
->cmd_q
[i
];
308 snprintf(name
, MAX_NAME_LEN
- 1, "q%d", cmd_q
->id
);
311 debugfs_create_dir(name
, ccp
->debugfs_instance
);
313 debugfs_create_file("stats", 0600, debugfs_q_instance
, cmd_q
,
314 &ccp_debugfs_queue_ops
);
320 void ccp5_debugfs_destroy(void)
322 debugfs_remove_recursive(ccp_debugfs_dir
);