root/arch/mips/crypto/crc32-mips.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. crc32_mips_le_hw
  2. crc32c_mips_le_hw
  3. chksum_init
  4. chksum_setkey
  5. chksum_update
  6. chksumc_update
  7. chksum_final
  8. chksumc_final
  9. __chksum_finup
  10. __chksumc_finup
  11. chksum_finup
  12. chksumc_finup
  13. chksum_digest
  14. chksumc_digest
  15. chksum_cra_init
  16. crc32_mod_init
  17. crc32_mod_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * crc32-mips.c - CRC32 and CRC32C using optional MIPSr6 instructions
   4  *
   5  * Module based on arm64/crypto/crc32-arm.c
   6  *
   7  * Copyright (C) 2014 Linaro Ltd <yazen.ghannam@linaro.org>
   8  * Copyright (C) 2018 MIPS Tech, LLC
   9  */
  10 
  11 #include <linux/unaligned/access_ok.h>
  12 #include <linux/cpufeature.h>
  13 #include <linux/init.h>
  14 #include <linux/kernel.h>
  15 #include <linux/module.h>
  16 #include <linux/string.h>
  17 #include <asm/mipsregs.h>
  18 
  19 #include <crypto/internal/hash.h>
  20 
  21 enum crc_op_size {
  22         b, h, w, d,
  23 };
  24 
  25 enum crc_type {
  26         crc32,
  27         crc32c,
  28 };
  29 
  30 #ifndef TOOLCHAIN_SUPPORTS_CRC
  31 #define _ASM_MACRO_CRC32(OP, SZ, TYPE)                                    \
  32 _ASM_MACRO_3R(OP, rt, rs, rt2,                                            \
  33         ".ifnc  \\rt, \\rt2\n\t"                                          \
  34         ".error \"invalid operands \\\"" #OP " \\rt,\\rs,\\rt2\\\"\"\n\t" \
  35         ".endif\n\t"                                                      \
  36         _ASM_INSN_IF_MIPS(0x7c00000f | (__rt << 16) | (__rs << 21) |      \
  37                           ((SZ) <<  6) | ((TYPE) << 8))                   \
  38         _ASM_INSN32_IF_MM(0x00000030 | (__rs << 16) | (__rt << 21) |      \
  39                           ((SZ) << 14) | ((TYPE) << 3)))
  40 _ASM_MACRO_CRC32(crc32b,  0, 0);
  41 _ASM_MACRO_CRC32(crc32h,  1, 0);
  42 _ASM_MACRO_CRC32(crc32w,  2, 0);
  43 _ASM_MACRO_CRC32(crc32d,  3, 0);
  44 _ASM_MACRO_CRC32(crc32cb, 0, 1);
  45 _ASM_MACRO_CRC32(crc32ch, 1, 1);
  46 _ASM_MACRO_CRC32(crc32cw, 2, 1);
  47 _ASM_MACRO_CRC32(crc32cd, 3, 1);
  48 #define _ASM_SET_CRC ""
  49 #else /* !TOOLCHAIN_SUPPORTS_CRC */
  50 #define _ASM_SET_CRC ".set\tcrc\n\t"
  51 #endif
  52 
  53 #define _CRC32(crc, value, size, type)          \
  54 do {                                            \
  55         __asm__ __volatile__(                   \
  56                 ".set   push\n\t"               \
  57                 _ASM_SET_CRC                    \
  58                 #type #size "   %0, %1, %0\n\t" \
  59                 ".set   pop"                    \
  60                 : "+r" (crc)                    \
  61                 : "r" (value));                 \
  62 } while (0)
  63 
  64 #define CRC32(crc, value, size) \
  65         _CRC32(crc, value, size, crc32)
  66 
  67 #define CRC32C(crc, value, size) \
  68         _CRC32(crc, value, size, crc32c)
  69 
  70 static u32 crc32_mips_le_hw(u32 crc_, const u8 *p, unsigned int len)
  71 {
  72         u32 crc = crc_;
  73 
  74 #ifdef CONFIG_64BIT
  75         while (len >= sizeof(u64)) {
  76                 u64 value = get_unaligned_le64(p);
  77 
  78                 CRC32(crc, value, d);
  79                 p += sizeof(u64);
  80                 len -= sizeof(u64);
  81         }
  82 
  83         if (len & sizeof(u32)) {
  84 #else /* !CONFIG_64BIT */
  85         while (len >= sizeof(u32)) {
  86 #endif
  87                 u32 value = get_unaligned_le32(p);
  88 
  89                 CRC32(crc, value, w);
  90                 p += sizeof(u32);
  91                 len -= sizeof(u32);
  92         }
  93 
  94         if (len & sizeof(u16)) {
  95                 u16 value = get_unaligned_le16(p);
  96 
  97                 CRC32(crc, value, h);
  98                 p += sizeof(u16);
  99         }
 100 
 101         if (len & sizeof(u8)) {
 102                 u8 value = *p++;
 103 
 104                 CRC32(crc, value, b);
 105         }
 106 
 107         return crc;
 108 }
 109 
 110 static u32 crc32c_mips_le_hw(u32 crc_, const u8 *p, unsigned int len)
 111 {
 112         u32 crc = crc_;
 113 
 114 #ifdef CONFIG_64BIT
 115         while (len >= sizeof(u64)) {
 116                 u64 value = get_unaligned_le64(p);
 117 
 118                 CRC32C(crc, value, d);
 119                 p += sizeof(u64);
 120                 len -= sizeof(u64);
 121         }
 122 
 123         if (len & sizeof(u32)) {
 124 #else /* !CONFIG_64BIT */
 125         while (len >= sizeof(u32)) {
 126 #endif
 127                 u32 value = get_unaligned_le32(p);
 128 
 129                 CRC32C(crc, value, w);
 130                 p += sizeof(u32);
 131                 len -= sizeof(u32);
 132         }
 133 
 134         if (len & sizeof(u16)) {
 135                 u16 value = get_unaligned_le16(p);
 136 
 137                 CRC32C(crc, value, h);
 138                 p += sizeof(u16);
 139         }
 140 
 141         if (len & sizeof(u8)) {
 142                 u8 value = *p++;
 143 
 144                 CRC32C(crc, value, b);
 145         }
 146         return crc;
 147 }
 148 
 149 #define CHKSUM_BLOCK_SIZE       1
 150 #define CHKSUM_DIGEST_SIZE      4
 151 
 152 struct chksum_ctx {
 153         u32 key;
 154 };
 155 
 156 struct chksum_desc_ctx {
 157         u32 crc;
 158 };
 159 
 160 static int chksum_init(struct shash_desc *desc)
 161 {
 162         struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
 163         struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 164 
 165         ctx->crc = mctx->key;
 166 
 167         return 0;
 168 }
 169 
 170 /*
 171  * Setting the seed allows arbitrary accumulators and flexible XOR policy
 172  * If your algorithm starts with ~0, then XOR with ~0 before you set
 173  * the seed.
 174  */
 175 static int chksum_setkey(struct crypto_shash *tfm, const u8 *key,
 176                          unsigned int keylen)
 177 {
 178         struct chksum_ctx *mctx = crypto_shash_ctx(tfm);
 179 
 180         if (keylen != sizeof(mctx->key)) {
 181                 crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
 182                 return -EINVAL;
 183         }
 184         mctx->key = get_unaligned_le32(key);
 185         return 0;
 186 }
 187 
 188 static int chksum_update(struct shash_desc *desc, const u8 *data,
 189                          unsigned int length)
 190 {
 191         struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 192 
 193         ctx->crc = crc32_mips_le_hw(ctx->crc, data, length);
 194         return 0;
 195 }
 196 
 197 static int chksumc_update(struct shash_desc *desc, const u8 *data,
 198                          unsigned int length)
 199 {
 200         struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 201 
 202         ctx->crc = crc32c_mips_le_hw(ctx->crc, data, length);
 203         return 0;
 204 }
 205 
 206 static int chksum_final(struct shash_desc *desc, u8 *out)
 207 {
 208         struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 209 
 210         put_unaligned_le32(ctx->crc, out);
 211         return 0;
 212 }
 213 
 214 static int chksumc_final(struct shash_desc *desc, u8 *out)
 215 {
 216         struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 217 
 218         put_unaligned_le32(~ctx->crc, out);
 219         return 0;
 220 }
 221 
 222 static int __chksum_finup(u32 crc, const u8 *data, unsigned int len, u8 *out)
 223 {
 224         put_unaligned_le32(crc32_mips_le_hw(crc, data, len), out);
 225         return 0;
 226 }
 227 
 228 static int __chksumc_finup(u32 crc, const u8 *data, unsigned int len, u8 *out)
 229 {
 230         put_unaligned_le32(~crc32c_mips_le_hw(crc, data, len), out);
 231         return 0;
 232 }
 233 
 234 static int chksum_finup(struct shash_desc *desc, const u8 *data,
 235                         unsigned int len, u8 *out)
 236 {
 237         struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 238 
 239         return __chksum_finup(ctx->crc, data, len, out);
 240 }
 241 
 242 static int chksumc_finup(struct shash_desc *desc, const u8 *data,
 243                         unsigned int len, u8 *out)
 244 {
 245         struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 246 
 247         return __chksumc_finup(ctx->crc, data, len, out);
 248 }
 249 
 250 static int chksum_digest(struct shash_desc *desc, const u8 *data,
 251                          unsigned int length, u8 *out)
 252 {
 253         struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
 254 
 255         return __chksum_finup(mctx->key, data, length, out);
 256 }
 257 
 258 static int chksumc_digest(struct shash_desc *desc, const u8 *data,
 259                          unsigned int length, u8 *out)
 260 {
 261         struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
 262 
 263         return __chksumc_finup(mctx->key, data, length, out);
 264 }
 265 
 266 static int chksum_cra_init(struct crypto_tfm *tfm)
 267 {
 268         struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
 269 
 270         mctx->key = ~0;
 271         return 0;
 272 }
 273 
 274 static struct shash_alg crc32_alg = {
 275         .digestsize             =       CHKSUM_DIGEST_SIZE,
 276         .setkey                 =       chksum_setkey,
 277         .init                   =       chksum_init,
 278         .update                 =       chksum_update,
 279         .final                  =       chksum_final,
 280         .finup                  =       chksum_finup,
 281         .digest                 =       chksum_digest,
 282         .descsize               =       sizeof(struct chksum_desc_ctx),
 283         .base                   =       {
 284                 .cra_name               =       "crc32",
 285                 .cra_driver_name        =       "crc32-mips-hw",
 286                 .cra_priority           =       300,
 287                 .cra_flags              =       CRYPTO_ALG_OPTIONAL_KEY,
 288                 .cra_blocksize          =       CHKSUM_BLOCK_SIZE,
 289                 .cra_alignmask          =       0,
 290                 .cra_ctxsize            =       sizeof(struct chksum_ctx),
 291                 .cra_module             =       THIS_MODULE,
 292                 .cra_init               =       chksum_cra_init,
 293         }
 294 };
 295 
 296 static struct shash_alg crc32c_alg = {
 297         .digestsize             =       CHKSUM_DIGEST_SIZE,
 298         .setkey                 =       chksum_setkey,
 299         .init                   =       chksum_init,
 300         .update                 =       chksumc_update,
 301         .final                  =       chksumc_final,
 302         .finup                  =       chksumc_finup,
 303         .digest                 =       chksumc_digest,
 304         .descsize               =       sizeof(struct chksum_desc_ctx),
 305         .base                   =       {
 306                 .cra_name               =       "crc32c",
 307                 .cra_driver_name        =       "crc32c-mips-hw",
 308                 .cra_priority           =       300,
 309                 .cra_flags              =       CRYPTO_ALG_OPTIONAL_KEY,
 310                 .cra_blocksize          =       CHKSUM_BLOCK_SIZE,
 311                 .cra_alignmask          =       0,
 312                 .cra_ctxsize            =       sizeof(struct chksum_ctx),
 313                 .cra_module             =       THIS_MODULE,
 314                 .cra_init               =       chksum_cra_init,
 315         }
 316 };
 317 
 318 static int __init crc32_mod_init(void)
 319 {
 320         int err;
 321 
 322         err = crypto_register_shash(&crc32_alg);
 323 
 324         if (err)
 325                 return err;
 326 
 327         err = crypto_register_shash(&crc32c_alg);
 328 
 329         if (err) {
 330                 crypto_unregister_shash(&crc32_alg);
 331                 return err;
 332         }
 333 
 334         return 0;
 335 }
 336 
 337 static void __exit crc32_mod_exit(void)
 338 {
 339         crypto_unregister_shash(&crc32_alg);
 340         crypto_unregister_shash(&crc32c_alg);
 341 }
 342 
 343 MODULE_AUTHOR("Marcin Nowakowski <marcin.nowakowski@mips.com");
 344 MODULE_DESCRIPTION("CRC32 and CRC32C using optional MIPS instructions");
 345 MODULE_LICENSE("GPL v2");
 346 
 347 module_cpu_feature_match(MIPS_CRC32, crc32_mod_init);
 348 module_exit(crc32_mod_exit);

/* [<][>][^][v][top][bottom][index][help] */