crct10dif-ce-glue.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Accelerated CRC-T10DIF using arm64 NEON and Crypto Extensions instructions
  4. *
  5. * Copyright (C) 2016 - 2017 Linaro Ltd <[email protected]>
  6. */
  7. #include <linux/cpufeature.h>
  8. #include <linux/crc-t10dif.h>
  9. #include <linux/init.h>
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/string.h>
  13. #include <crypto/internal/hash.h>
  14. #include <crypto/internal/simd.h>
  15. #include <asm/neon.h>
  16. #include <asm/simd.h>
  17. #define CRC_T10DIF_PMULL_CHUNK_SIZE 16U
  18. asmlinkage u16 crc_t10dif_pmull_p8(u16 init_crc, const u8 *buf, size_t len);
  19. asmlinkage u16 crc_t10dif_pmull_p64(u16 init_crc, const u8 *buf, size_t len);
  20. static int crct10dif_init(struct shash_desc *desc)
  21. {
  22. u16 *crc = shash_desc_ctx(desc);
  23. *crc = 0;
  24. return 0;
  25. }
  26. static int crct10dif_update_pmull_p8(struct shash_desc *desc, const u8 *data,
  27. unsigned int length)
  28. {
  29. u16 *crc = shash_desc_ctx(desc);
  30. if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) {
  31. do {
  32. unsigned int chunk = length;
  33. if (chunk > SZ_4K + CRC_T10DIF_PMULL_CHUNK_SIZE)
  34. chunk = SZ_4K;
  35. kernel_neon_begin();
  36. *crc = crc_t10dif_pmull_p8(*crc, data, chunk);
  37. kernel_neon_end();
  38. data += chunk;
  39. length -= chunk;
  40. } while (length);
  41. } else {
  42. *crc = crc_t10dif_generic(*crc, data, length);
  43. }
  44. return 0;
  45. }
  46. static int crct10dif_update_pmull_p64(struct shash_desc *desc, const u8 *data,
  47. unsigned int length)
  48. {
  49. u16 *crc = shash_desc_ctx(desc);
  50. if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) {
  51. do {
  52. unsigned int chunk = length;
  53. if (chunk > SZ_4K + CRC_T10DIF_PMULL_CHUNK_SIZE)
  54. chunk = SZ_4K;
  55. kernel_neon_begin();
  56. *crc = crc_t10dif_pmull_p64(*crc, data, chunk);
  57. kernel_neon_end();
  58. data += chunk;
  59. length -= chunk;
  60. } while (length);
  61. } else {
  62. *crc = crc_t10dif_generic(*crc, data, length);
  63. }
  64. return 0;
  65. }
  66. static int crct10dif_final(struct shash_desc *desc, u8 *out)
  67. {
  68. u16 *crc = shash_desc_ctx(desc);
  69. *(u16 *)out = *crc;
  70. return 0;
  71. }
  72. static struct shash_alg crc_t10dif_alg[] = {{
  73. .digestsize = CRC_T10DIF_DIGEST_SIZE,
  74. .init = crct10dif_init,
  75. .update = crct10dif_update_pmull_p8,
  76. .final = crct10dif_final,
  77. .descsize = CRC_T10DIF_DIGEST_SIZE,
  78. .base.cra_name = "crct10dif",
  79. .base.cra_driver_name = "crct10dif-arm64-neon",
  80. .base.cra_priority = 100,
  81. .base.cra_blocksize = CRC_T10DIF_BLOCK_SIZE,
  82. .base.cra_module = THIS_MODULE,
  83. }, {
  84. .digestsize = CRC_T10DIF_DIGEST_SIZE,
  85. .init = crct10dif_init,
  86. .update = crct10dif_update_pmull_p64,
  87. .final = crct10dif_final,
  88. .descsize = CRC_T10DIF_DIGEST_SIZE,
  89. .base.cra_name = "crct10dif",
  90. .base.cra_driver_name = "crct10dif-arm64-ce",
  91. .base.cra_priority = 200,
  92. .base.cra_blocksize = CRC_T10DIF_BLOCK_SIZE,
  93. .base.cra_module = THIS_MODULE,
  94. }};
  95. static int __init crc_t10dif_mod_init(void)
  96. {
  97. if (cpu_have_named_feature(PMULL))
  98. return crypto_register_shashes(crc_t10dif_alg,
  99. ARRAY_SIZE(crc_t10dif_alg));
  100. else
  101. /* only register the first array element */
  102. return crypto_register_shash(crc_t10dif_alg);
  103. }
  104. static void __exit crc_t10dif_mod_exit(void)
  105. {
  106. if (cpu_have_named_feature(PMULL))
  107. crypto_unregister_shashes(crc_t10dif_alg,
  108. ARRAY_SIZE(crc_t10dif_alg));
  109. else
  110. crypto_unregister_shash(crc_t10dif_alg);
  111. }
  112. module_cpu_feature_match(ASIMD, crc_t10dif_mod_init);
  113. module_exit(crc_t10dif_mod_exit);
  114. MODULE_AUTHOR("Ard Biesheuvel <[email protected]>");
  115. MODULE_LICENSE("GPL v2");
  116. MODULE_ALIAS_CRYPTO("crct10dif");
  117. MODULE_ALIAS_CRYPTO("crct10dif-arm64-ce");