Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[sfrench/cifs-2.6.git] / drivers / crypto / ccp / ccp-debugfs.c
1 /*
2  * AMD Cryptographic Coprocessor (CCP) driver
3  *
4  * Copyright (C) 2017 Advanced Micro Devices, Inc.
5  *
6  * Author: Gary R Hook <gary.hook@amd.com>
7  *
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.
11  */
12
13 #include <linux/debugfs.h>
14 #include <linux/ccp.h>
15
16 #include "ccp-dev.h"
17
18 /* DebugFS helpers */
19 #define OBUFP           (obuf + oboff)
20 #define OBUFLEN         512
21 #define OBUFSPC         (OBUFLEN - oboff)
22 #define OSCNPRINTF(fmt, ...) \
23                 scnprintf(OBUFP, OBUFSPC, fmt, ## __VA_ARGS__)
24
25 #define BUFLEN  63
26
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)
44
45 static ssize_t ccp5_debugfs_info_read(struct file *filp, char __user *ubuf,
46                                       size_t count, loff_t *offp)
47 {
48         struct ccp_device *ccp = filp->private_data;
49         unsigned int oboff = 0;
50         unsigned int regval;
51         ssize_t ret;
52         char *obuf;
53
54         if (!ccp)
55                 return 0;
56
57         obuf = kmalloc(OBUFLEN, GFP_KERNEL);
58         if (!obuf)
59                 return -ENOMEM;
60
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);
65
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);
90
91         ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff);
92         kfree(obuf);
93
94         return ret;
95 }
96
97 /* Return a formatted buffer containing the current
98  * statistics across all queues for a CCP.
99  */
100 static ssize_t ccp5_debugfs_stats_read(struct file *filp, char __user *ubuf,
101                                        size_t count, loff_t *offp)
102 {
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;
113         ssize_t ret = 0;
114         unsigned int i;
115         char *obuf;
116
117         for (i = 0; i < ccp->cmd_q_count; i++) {
118                 struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
119
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;
128         }
129
130         obuf = kmalloc(OBUFLEN, GFP_KERNEL);
131         if (!obuf)
132                 return -ENOMEM;
133
134         oboff += OSCNPRINTF("Total Interrupts Handled: %ld\n",
135                             ccp->total_interrupts);
136         oboff += OSCNPRINTF("        Total Operations: %ld\n",
137                             total_ops);
138         oboff += OSCNPRINTF("                     AES: %ld\n",
139                             total_aes_ops);
140         oboff += OSCNPRINTF("                 XTS AES: %ld\n",
141                             total_xts_aes_ops);
142         oboff += OSCNPRINTF("                     SHA: %ld\n",
143                             total_3des_ops);
144         oboff += OSCNPRINTF("                     SHA: %ld\n",
145                             total_sha_ops);
146         oboff += OSCNPRINTF("                     RSA: %ld\n",
147                             total_rsa_ops);
148         oboff += OSCNPRINTF("               Pass-Thru: %ld\n",
149                             total_pt_ops);
150         oboff += OSCNPRINTF("                     ECC: %ld\n",
151                             total_ecc_ops);
152
153         ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff);
154         kfree(obuf);
155
156         return ret;
157 }
158
159 /* Reset the counters in a queue
160  */
161 static void ccp5_debugfs_reset_queue_stats(struct ccp_cmd_queue *cmd_q)
162 {
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;
171 }
172
173 /* A value was written to the stats variable, which
174  * should be used to reset the queue counters across
175  * that device.
176  */
177 static ssize_t ccp5_debugfs_stats_write(struct file *filp,
178                                         const char __user *ubuf,
179                                         size_t count, loff_t *offp)
180 {
181         struct ccp_device *ccp = filp->private_data;
182         int i;
183
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;
187
188         return count;
189 }
190
191 /* Return a formatted buffer containing the current information
192  * for that queue
193  */
194 static ssize_t ccp5_debugfs_queue_read(struct file *filp, char __user *ubuf,
195                                        size_t count, loff_t *offp)
196 {
197         struct ccp_cmd_queue *cmd_q = filp->private_data;
198         unsigned int oboff = 0;
199         unsigned int regval;
200         ssize_t ret;
201         char *obuf;
202
203         if (!cmd_q)
204                 return 0;
205
206         obuf = kmalloc(OBUFLEN, GFP_KERNEL);
207         if (!obuf)
208                 return -ENOMEM;
209
210         oboff += OSCNPRINTF("  Total Queue Operations: %ld\n",
211                             cmd_q->total_ops);
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);
226
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");
238
239         ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff);
240         kfree(obuf);
241
242         return ret;
243 }
244
245 /* A value was written to the stats variable for a
246  * queue. Reset the queue counters to this value.
247  */
248 static ssize_t ccp5_debugfs_queue_write(struct file *filp,
249                                         const char __user *ubuf,
250                                         size_t count, loff_t *offp)
251 {
252         struct ccp_cmd_queue *cmd_q = filp->private_data;
253
254         ccp5_debugfs_reset_queue_stats(cmd_q);
255
256         return count;
257 }
258
259 static const struct file_operations ccp_debugfs_info_ops = {
260         .owner = THIS_MODULE,
261         .open = simple_open,
262         .read = ccp5_debugfs_info_read,
263         .write = NULL,
264 };
265
266 static const struct file_operations ccp_debugfs_queue_ops = {
267         .owner = THIS_MODULE,
268         .open = simple_open,
269         .read = ccp5_debugfs_queue_read,
270         .write = ccp5_debugfs_queue_write,
271 };
272
273 static const struct file_operations ccp_debugfs_stats_ops = {
274         .owner = THIS_MODULE,
275         .open = simple_open,
276         .read = ccp5_debugfs_stats_read,
277         .write = ccp5_debugfs_stats_write,
278 };
279
280 static struct dentry *ccp_debugfs_dir;
281 static DEFINE_RWLOCK(ccp_debugfs_lock);
282
283 #define MAX_NAME_LEN    20
284
285 void ccp5_debugfs_setup(struct ccp_device *ccp)
286 {
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;
293         unsigned long flags;
294         int i;
295
296         if (!debugfs_initialized())
297                 return;
298
299         write_lock_irqsave(&ccp_debugfs_lock, flags);
300         if (!ccp_debugfs_dir)
301                 ccp_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
302         write_unlock_irqrestore(&ccp_debugfs_lock, flags);
303         if (!ccp_debugfs_dir)
304                 return;
305
306         ccp->debugfs_instance = debugfs_create_dir(ccp->name, ccp_debugfs_dir);
307         if (!ccp->debugfs_instance)
308                 goto err;
309
310         debugfs_info = debugfs_create_file("info", 0400,
311                                            ccp->debugfs_instance, ccp,
312                                            &ccp_debugfs_info_ops);
313         if (!debugfs_info)
314                 goto err;
315
316         debugfs_stats = debugfs_create_file("stats", 0600,
317                                             ccp->debugfs_instance, ccp,
318                                             &ccp_debugfs_stats_ops);
319         if (!debugfs_stats)
320                 goto err;
321
322         for (i = 0; i < ccp->cmd_q_count; i++) {
323                 cmd_q = &ccp->cmd_q[i];
324
325                 snprintf(name, MAX_NAME_LEN - 1, "q%d", cmd_q->id);
326
327                 debugfs_q_instance =
328                         debugfs_create_dir(name, ccp->debugfs_instance);
329                 if (!debugfs_q_instance)
330                         goto err;
331
332                 debugfs_q_stats =
333                         debugfs_create_file("stats", 0600,
334                                             debugfs_q_instance, cmd_q,
335                                             &ccp_debugfs_queue_ops);
336                 if (!debugfs_q_stats)
337                         goto err;
338         }
339
340         return;
341
342 err:
343         debugfs_remove_recursive(ccp->debugfs_instance);
344 }
345
346 void ccp5_debugfs_destroy(void)
347 {
348         debugfs_remove_recursive(ccp_debugfs_dir);
349 }