linux/drivers/crypto/ccp/ccp-debugfs.c
<<
>>
Prefs
   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
  42static 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 */
  97static 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 */
 158static 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 */
 174static 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 */
 191static 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 */
 245static 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
 256static 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
 263static 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
 270static 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
 277static struct dentry *ccp_debugfs_dir;
 278static DEFINE_MUTEX(ccp_debugfs_lock);
 279
 280#define MAX_NAME_LEN    20
 281
 282void 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
 320void ccp5_debugfs_destroy(void)
 321{
 322        debugfs_remove_recursive(ccp_debugfs_dir);
 323}
 324