Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2016 Broadcom
0004  */
0005 
0006 #include <linux/debugfs.h>
0007 
0008 #include "cipher.h"
0009 #include "util.h"
0010 
0011 /* offset of SPU_OFIFO_CTRL register */
0012 #define SPU_OFIFO_CTRL      0x40
0013 #define SPU_FIFO_WATERMARK  0x1FF
0014 
0015 /**
0016  * spu_sg_at_offset() - Find the scatterlist entry at a given distance from the
0017  * start of a scatterlist.
0018  * @sg:         [in]  Start of a scatterlist
0019  * @skip:       [in]  Distance from the start of the scatterlist, in bytes
0020  * @sge:        [out] Scatterlist entry at skip bytes from start
0021  * @sge_offset: [out] Number of bytes from start of sge buffer to get to
0022  *                    requested distance.
0023  *
0024  * Return: 0 if entry found at requested distance
0025  *         < 0 otherwise
0026  */
0027 int spu_sg_at_offset(struct scatterlist *sg, unsigned int skip,
0028              struct scatterlist **sge, unsigned int *sge_offset)
0029 {
0030     /* byte index from start of sg to the end of the previous entry */
0031     unsigned int index = 0;
0032     /* byte index from start of sg to the end of the current entry */
0033     unsigned int next_index;
0034 
0035     next_index = sg->length;
0036     while (next_index <= skip) {
0037         sg = sg_next(sg);
0038         index = next_index;
0039         if (!sg)
0040             return -EINVAL;
0041         next_index += sg->length;
0042     }
0043 
0044     *sge_offset = skip - index;
0045     *sge = sg;
0046     return 0;
0047 }
0048 
0049 /* Copy len bytes of sg data, starting at offset skip, to a dest buffer */
0050 void sg_copy_part_to_buf(struct scatterlist *src, u8 *dest,
0051              unsigned int len, unsigned int skip)
0052 {
0053     size_t copied;
0054     unsigned int nents = sg_nents(src);
0055 
0056     copied = sg_pcopy_to_buffer(src, nents, dest, len, skip);
0057     if (copied != len) {
0058         flow_log("%s copied %u bytes of %u requested. ",
0059              __func__, (u32)copied, len);
0060         flow_log("sg with %u entries and skip %u\n", nents, skip);
0061     }
0062 }
0063 
0064 /*
0065  * Copy data into a scatterlist starting at a specified offset in the
0066  * scatterlist. Specifically, copy len bytes of data in the buffer src
0067  * into the scatterlist dest, starting skip bytes into the scatterlist.
0068  */
0069 void sg_copy_part_from_buf(struct scatterlist *dest, u8 *src,
0070                unsigned int len, unsigned int skip)
0071 {
0072     size_t copied;
0073     unsigned int nents = sg_nents(dest);
0074 
0075     copied = sg_pcopy_from_buffer(dest, nents, src, len, skip);
0076     if (copied != len) {
0077         flow_log("%s copied %u bytes of %u requested. ",
0078              __func__, (u32)copied, len);
0079         flow_log("sg with %u entries and skip %u\n", nents, skip);
0080     }
0081 }
0082 
0083 /**
0084  * spu_sg_count() - Determine number of elements in scatterlist to provide a
0085  * specified number of bytes.
0086  * @sg_list:  scatterlist to examine
0087  * @skip:     index of starting point
0088  * @nbytes:   consider elements of scatterlist until reaching this number of
0089  *        bytes
0090  *
0091  * Return: the number of sg entries contributing to nbytes of data
0092  */
0093 int spu_sg_count(struct scatterlist *sg_list, unsigned int skip, int nbytes)
0094 {
0095     struct scatterlist *sg;
0096     int sg_nents = 0;
0097     unsigned int offset;
0098 
0099     if (!sg_list)
0100         return 0;
0101 
0102     if (spu_sg_at_offset(sg_list, skip, &sg, &offset) < 0)
0103         return 0;
0104 
0105     while (sg && (nbytes > 0)) {
0106         sg_nents++;
0107         nbytes -= (sg->length - offset);
0108         offset = 0;
0109         sg = sg_next(sg);
0110     }
0111     return sg_nents;
0112 }
0113 
0114 /**
0115  * spu_msg_sg_add() - Copy scatterlist entries from one sg to another, up to a
0116  * given length.
0117  * @to_sg:       scatterlist to copy to
0118  * @from_sg:     scatterlist to copy from
0119  * @from_skip:   number of bytes to skip in from_sg. Non-zero when previous
0120  *       request included part of the buffer in entry in from_sg.
0121  *       Assumes from_skip < from_sg->length.
0122  * @from_nents:  number of entries in from_sg
0123  * @length:      number of bytes to copy. may reach this limit before exhausting
0124  *       from_sg.
0125  *
0126  * Copies the entries themselves, not the data in the entries. Assumes to_sg has
0127  * enough entries. Does not limit the size of an individual buffer in to_sg.
0128  *
0129  * to_sg, from_sg, skip are all updated to end of copy
0130  *
0131  * Return: Number of bytes copied
0132  */
0133 u32 spu_msg_sg_add(struct scatterlist **to_sg,
0134            struct scatterlist **from_sg, u32 *from_skip,
0135            u8 from_nents, u32 length)
0136 {
0137     struct scatterlist *sg; /* an entry in from_sg */
0138     struct scatterlist *to = *to_sg;
0139     struct scatterlist *from = *from_sg;
0140     u32 skip = *from_skip;
0141     u32 offset;
0142     int i;
0143     u32 entry_len = 0;
0144     u32 frag_len = 0;   /* length of entry added to to_sg */
0145     u32 copied = 0;     /* number of bytes copied so far */
0146 
0147     if (length == 0)
0148         return 0;
0149 
0150     for_each_sg(from, sg, from_nents, i) {
0151         /* number of bytes in this from entry not yet used */
0152         entry_len = sg->length - skip;
0153         frag_len = min(entry_len, length - copied);
0154         offset = sg->offset + skip;
0155         if (frag_len)
0156             sg_set_page(to++, sg_page(sg), frag_len, offset);
0157         copied += frag_len;
0158         if (copied == entry_len) {
0159             /* used up all of from entry */
0160             skip = 0;   /* start at beginning of next entry */
0161         }
0162         if (copied == length)
0163             break;
0164     }
0165     *to_sg = to;
0166     *from_sg = sg;
0167     if (frag_len < entry_len)
0168         *from_skip = skip + frag_len;
0169     else
0170         *from_skip = 0;
0171 
0172     return copied;
0173 }
0174 
0175 void add_to_ctr(u8 *ctr_pos, unsigned int increment)
0176 {
0177     __be64 *high_be = (__be64 *)ctr_pos;
0178     __be64 *low_be = high_be + 1;
0179     u64 orig_low = __be64_to_cpu(*low_be);
0180     u64 new_low = orig_low + (u64)increment;
0181 
0182     *low_be = __cpu_to_be64(new_low);
0183     if (new_low < orig_low)
0184         /* there was a carry from the low 8 bytes */
0185         *high_be = __cpu_to_be64(__be64_to_cpu(*high_be) + 1);
0186 }
0187 
0188 struct sdesc {
0189     struct shash_desc shash;
0190     char ctx[];
0191 };
0192 
0193 /**
0194  * do_shash() - Do a synchronous hash operation in software
0195  * @name:       The name of the hash algorithm
0196  * @result:     Buffer where digest is to be written
0197  * @data1:      First part of data to hash. May be NULL.
0198  * @data1_len:  Length of data1, in bytes
0199  * @data2:      Second part of data to hash. May be NULL.
0200  * @data2_len:  Length of data2, in bytes
0201  * @key:    Key (if keyed hash)
0202  * @key_len:    Length of key, in bytes (or 0 if non-keyed hash)
0203  *
0204  * Note that the crypto API will not select this driver's own transform because
0205  * this driver only registers asynchronous algos.
0206  *
0207  * Return: 0 if hash successfully stored in result
0208  *         < 0 otherwise
0209  */
0210 int do_shash(unsigned char *name, unsigned char *result,
0211          const u8 *data1, unsigned int data1_len,
0212          const u8 *data2, unsigned int data2_len,
0213          const u8 *key, unsigned int key_len)
0214 {
0215     int rc;
0216     unsigned int size;
0217     struct crypto_shash *hash;
0218     struct sdesc *sdesc;
0219 
0220     hash = crypto_alloc_shash(name, 0, 0);
0221     if (IS_ERR(hash)) {
0222         rc = PTR_ERR(hash);
0223         pr_err("%s: Crypto %s allocation error %d\n", __func__, name, rc);
0224         return rc;
0225     }
0226 
0227     size = sizeof(struct shash_desc) + crypto_shash_descsize(hash);
0228     sdesc = kmalloc(size, GFP_KERNEL);
0229     if (!sdesc) {
0230         rc = -ENOMEM;
0231         goto do_shash_err;
0232     }
0233     sdesc->shash.tfm = hash;
0234 
0235     if (key_len > 0) {
0236         rc = crypto_shash_setkey(hash, key, key_len);
0237         if (rc) {
0238             pr_err("%s: Could not setkey %s shash\n", __func__, name);
0239             goto do_shash_err;
0240         }
0241     }
0242 
0243     rc = crypto_shash_init(&sdesc->shash);
0244     if (rc) {
0245         pr_err("%s: Could not init %s shash\n", __func__, name);
0246         goto do_shash_err;
0247     }
0248     rc = crypto_shash_update(&sdesc->shash, data1, data1_len);
0249     if (rc) {
0250         pr_err("%s: Could not update1\n", __func__);
0251         goto do_shash_err;
0252     }
0253     if (data2 && data2_len) {
0254         rc = crypto_shash_update(&sdesc->shash, data2, data2_len);
0255         if (rc) {
0256             pr_err("%s: Could not update2\n", __func__);
0257             goto do_shash_err;
0258         }
0259     }
0260     rc = crypto_shash_final(&sdesc->shash, result);
0261     if (rc)
0262         pr_err("%s: Could not generate %s hash\n", __func__, name);
0263 
0264 do_shash_err:
0265     crypto_free_shash(hash);
0266     kfree(sdesc);
0267 
0268     return rc;
0269 }
0270 
0271 #ifdef DEBUG
0272 /* Dump len bytes of a scatterlist starting at skip bytes into the sg */
0273 void __dump_sg(struct scatterlist *sg, unsigned int skip, unsigned int len)
0274 {
0275     u8 dbuf[16];
0276     unsigned int idx = skip;
0277     unsigned int num_out = 0;   /* number of bytes dumped so far */
0278     unsigned int count;
0279 
0280     if (packet_debug_logging) {
0281         while (num_out < len) {
0282             count = (len - num_out > 16) ? 16 : len - num_out;
0283             sg_copy_part_to_buf(sg, dbuf, count, idx);
0284             num_out += count;
0285             print_hex_dump(KERN_ALERT, "  sg: ", DUMP_PREFIX_NONE,
0286                        4, 1, dbuf, count, false);
0287             idx += 16;
0288         }
0289     }
0290     if (debug_logging_sleep)
0291         msleep(debug_logging_sleep);
0292 }
0293 #endif
0294 
0295 /* Returns the name for a given cipher alg/mode */
0296 char *spu_alg_name(enum spu_cipher_alg alg, enum spu_cipher_mode mode)
0297 {
0298     switch (alg) {
0299     case CIPHER_ALG_RC4:
0300         return "rc4";
0301     case CIPHER_ALG_AES:
0302         switch (mode) {
0303         case CIPHER_MODE_CBC:
0304             return "cbc(aes)";
0305         case CIPHER_MODE_ECB:
0306             return "ecb(aes)";
0307         case CIPHER_MODE_OFB:
0308             return "ofb(aes)";
0309         case CIPHER_MODE_CFB:
0310             return "cfb(aes)";
0311         case CIPHER_MODE_CTR:
0312             return "ctr(aes)";
0313         case CIPHER_MODE_XTS:
0314             return "xts(aes)";
0315         case CIPHER_MODE_GCM:
0316             return "gcm(aes)";
0317         default:
0318             return "aes";
0319         }
0320         break;
0321     case CIPHER_ALG_DES:
0322         switch (mode) {
0323         case CIPHER_MODE_CBC:
0324             return "cbc(des)";
0325         case CIPHER_MODE_ECB:
0326             return "ecb(des)";
0327         case CIPHER_MODE_CTR:
0328             return "ctr(des)";
0329         default:
0330             return "des";
0331         }
0332         break;
0333     case CIPHER_ALG_3DES:
0334         switch (mode) {
0335         case CIPHER_MODE_CBC:
0336             return "cbc(des3_ede)";
0337         case CIPHER_MODE_ECB:
0338             return "ecb(des3_ede)";
0339         case CIPHER_MODE_CTR:
0340             return "ctr(des3_ede)";
0341         default:
0342             return "3des";
0343         }
0344         break;
0345     default:
0346         return "other";
0347     }
0348 }
0349 
0350 static ssize_t spu_debugfs_read(struct file *filp, char __user *ubuf,
0351                 size_t count, loff_t *offp)
0352 {
0353     struct bcm_device_private *ipriv;
0354     char *buf;
0355     ssize_t ret, out_offset, out_count;
0356     int i;
0357     u32 fifo_len;
0358     u32 spu_ofifo_ctrl;
0359     u32 alg;
0360     u32 mode;
0361     u32 op_cnt;
0362 
0363     out_count = 2048;
0364 
0365     buf = kmalloc(out_count, GFP_KERNEL);
0366     if (!buf)
0367         return -ENOMEM;
0368 
0369     ipriv = filp->private_data;
0370     out_offset = 0;
0371     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0372                    "Number of SPUs.........%u\n",
0373                    ipriv->spu.num_spu);
0374     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0375                    "Current sessions.......%u\n",
0376                    atomic_read(&ipriv->session_count));
0377     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0378                    "Session count..........%u\n",
0379                    atomic_read(&ipriv->stream_count));
0380     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0381                    "Cipher setkey..........%u\n",
0382                    atomic_read(&ipriv->setkey_cnt[SPU_OP_CIPHER]));
0383     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0384                    "Cipher Ops.............%u\n",
0385                    atomic_read(&ipriv->op_counts[SPU_OP_CIPHER]));
0386     for (alg = 0; alg < CIPHER_ALG_LAST; alg++) {
0387         for (mode = 0; mode < CIPHER_MODE_LAST; mode++) {
0388             op_cnt = atomic_read(&ipriv->cipher_cnt[alg][mode]);
0389             if (op_cnt) {
0390                 out_offset += scnprintf(buf + out_offset,
0391                                out_count - out_offset,
0392                    "  %-13s%11u\n",
0393                    spu_alg_name(alg, mode), op_cnt);
0394             }
0395         }
0396     }
0397     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0398                    "Hash Ops...............%u\n",
0399                    atomic_read(&ipriv->op_counts[SPU_OP_HASH]));
0400     for (alg = 0; alg < HASH_ALG_LAST; alg++) {
0401         op_cnt = atomic_read(&ipriv->hash_cnt[alg]);
0402         if (op_cnt) {
0403             out_offset += scnprintf(buf + out_offset,
0404                            out_count - out_offset,
0405                "  %-13s%11u\n",
0406                hash_alg_name[alg], op_cnt);
0407         }
0408     }
0409     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0410                    "HMAC setkey............%u\n",
0411                    atomic_read(&ipriv->setkey_cnt[SPU_OP_HMAC]));
0412     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0413                    "HMAC Ops...............%u\n",
0414                    atomic_read(&ipriv->op_counts[SPU_OP_HMAC]));
0415     for (alg = 0; alg < HASH_ALG_LAST; alg++) {
0416         op_cnt = atomic_read(&ipriv->hmac_cnt[alg]);
0417         if (op_cnt) {
0418             out_offset += scnprintf(buf + out_offset,
0419                            out_count - out_offset,
0420                "  %-13s%11u\n",
0421                hash_alg_name[alg], op_cnt);
0422         }
0423     }
0424     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0425                    "AEAD setkey............%u\n",
0426                    atomic_read(&ipriv->setkey_cnt[SPU_OP_AEAD]));
0427 
0428     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0429                    "AEAD Ops...............%u\n",
0430                    atomic_read(&ipriv->op_counts[SPU_OP_AEAD]));
0431     for (alg = 0; alg < AEAD_TYPE_LAST; alg++) {
0432         op_cnt = atomic_read(&ipriv->aead_cnt[alg]);
0433         if (op_cnt) {
0434             out_offset += scnprintf(buf + out_offset,
0435                            out_count - out_offset,
0436                "  %-13s%11u\n",
0437                aead_alg_name[alg], op_cnt);
0438         }
0439     }
0440     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0441                    "Bytes of req data......%llu\n",
0442                    (u64)atomic64_read(&ipriv->bytes_out));
0443     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0444                    "Bytes of resp data.....%llu\n",
0445                    (u64)atomic64_read(&ipriv->bytes_in));
0446     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0447                    "Mailbox full...........%u\n",
0448                    atomic_read(&ipriv->mb_no_spc));
0449     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0450                    "Mailbox send failures..%u\n",
0451                    atomic_read(&ipriv->mb_send_fail));
0452     out_offset += scnprintf(buf + out_offset, out_count - out_offset,
0453                    "Check ICV errors.......%u\n",
0454                    atomic_read(&ipriv->bad_icv));
0455     if (ipriv->spu.spu_type == SPU_TYPE_SPUM)
0456         for (i = 0; i < ipriv->spu.num_spu; i++) {
0457             spu_ofifo_ctrl = ioread32(ipriv->spu.reg_vbase[i] +
0458                           SPU_OFIFO_CTRL);
0459             fifo_len = spu_ofifo_ctrl & SPU_FIFO_WATERMARK;
0460             out_offset += scnprintf(buf + out_offset,
0461                            out_count - out_offset,
0462                        "SPU %d output FIFO high water.....%u\n",
0463                        i, fifo_len);
0464         }
0465 
0466     if (out_offset > out_count)
0467         out_offset = out_count;
0468 
0469     ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
0470     kfree(buf);
0471     return ret;
0472 }
0473 
0474 static const struct file_operations spu_debugfs_stats = {
0475     .owner = THIS_MODULE,
0476     .open = simple_open,
0477     .read = spu_debugfs_read,
0478 };
0479 
0480 /*
0481  * Create the debug FS directories. If the top-level directory has not yet
0482  * been created, create it now. Create a stats file in this directory for
0483  * a SPU.
0484  */
0485 void spu_setup_debugfs(void)
0486 {
0487     if (!debugfs_initialized())
0488         return;
0489 
0490     if (!iproc_priv.debugfs_dir)
0491         iproc_priv.debugfs_dir = debugfs_create_dir(KBUILD_MODNAME,
0492                                 NULL);
0493 
0494     if (!iproc_priv.debugfs_stats)
0495         /* Create file with permissions S_IRUSR */
0496         debugfs_create_file("stats", 0400, iproc_priv.debugfs_dir,
0497                     &iproc_priv, &spu_debugfs_stats);
0498 }
0499 
0500 void spu_free_debugfs(void)
0501 {
0502     debugfs_remove_recursive(iproc_priv.debugfs_dir);
0503     iproc_priv.debugfs_dir = NULL;
0504 }
0505 
0506 /**
0507  * format_value_ccm() - Format a value into a buffer, using a specified number
0508  *          of bytes (i.e. maybe writing value X into a 4 byte
0509  *          buffer, or maybe into a 12 byte buffer), as per the
0510  *          SPU CCM spec.
0511  *
0512  * @val:        value to write (up to max of unsigned int)
0513  * @buf:        (pointer to) buffer to write the value
0514  * @len:        number of bytes to use (0 to 255)
0515  *
0516  */
0517 void format_value_ccm(unsigned int val, u8 *buf, u8 len)
0518 {
0519     int i;
0520 
0521     /* First clear full output buffer */
0522     memset(buf, 0, len);
0523 
0524     /* Then, starting from right side, fill in with data */
0525     for (i = 0; i < len; i++) {
0526         buf[len - i - 1] = (val >> (8 * i)) & 0xff;
0527         if (i >= 3)
0528             break;  /* Only handle up to 32 bits of 'val' */
0529     }
0530 }