crct10dif-vpmsum_glue.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Calculate a CRC T10-DIF with vpmsum acceleration
  4. *
  5. * Copyright 2017, Daniel Axtens, IBM Corporation.
  6. * [based on crc32c-vpmsum_glue.c]
  7. */
  8. #include <linux/crc-t10dif.h>
  9. #include <crypto/internal/hash.h>
  10. #include <crypto/internal/simd.h>
  11. #include <linux/init.h>
  12. #include <linux/module.h>
  13. #include <linux/string.h>
  14. #include <linux/kernel.h>
  15. #include <linux/cpufeature.h>
  16. #include <asm/simd.h>
  17. #include <asm/switch_to.h>
  18. #define VMX_ALIGN 16
  19. #define VMX_ALIGN_MASK (VMX_ALIGN-1)
  20. #define VECTOR_BREAKPOINT 64
  21. u32 __crct10dif_vpmsum(u32 crc, unsigned char const *p, size_t len);
  22. static u16 crct10dif_vpmsum(u16 crci, unsigned char const *p, size_t len)
  23. {
  24. unsigned int prealign;
  25. unsigned int tail;
  26. u32 crc = crci;
  27. if (len < (VECTOR_BREAKPOINT + VMX_ALIGN) || !crypto_simd_usable())
  28. return crc_t10dif_generic(crc, p, len);
  29. if ((unsigned long)p & VMX_ALIGN_MASK) {
  30. prealign = VMX_ALIGN - ((unsigned long)p & VMX_ALIGN_MASK);
  31. crc = crc_t10dif_generic(crc, p, prealign);
  32. len -= prealign;
  33. p += prealign;
  34. }
  35. if (len & ~VMX_ALIGN_MASK) {
  36. crc <<= 16;
  37. preempt_disable();
  38. pagefault_disable();
  39. enable_kernel_altivec();
  40. crc = __crct10dif_vpmsum(crc, p, len & ~VMX_ALIGN_MASK);
  41. disable_kernel_altivec();
  42. pagefault_enable();
  43. preempt_enable();
  44. crc >>= 16;
  45. }
  46. tail = len & VMX_ALIGN_MASK;
  47. if (tail) {
  48. p += len & ~VMX_ALIGN_MASK;
  49. crc = crc_t10dif_generic(crc, p, tail);
  50. }
  51. return crc & 0xffff;
  52. }
  53. static int crct10dif_vpmsum_init(struct shash_desc *desc)
  54. {
  55. u16 *crc = shash_desc_ctx(desc);
  56. *crc = 0;
  57. return 0;
  58. }
  59. static int crct10dif_vpmsum_update(struct shash_desc *desc, const u8 *data,
  60. unsigned int length)
  61. {
  62. u16 *crc = shash_desc_ctx(desc);
  63. *crc = crct10dif_vpmsum(*crc, data, length);
  64. return 0;
  65. }
  66. static int crct10dif_vpmsum_final(struct shash_desc *desc, u8 *out)
  67. {
  68. u16 *crcp = shash_desc_ctx(desc);
  69. *(u16 *)out = *crcp;
  70. return 0;
  71. }
  72. static struct shash_alg alg = {
  73. .init = crct10dif_vpmsum_init,
  74. .update = crct10dif_vpmsum_update,
  75. .final = crct10dif_vpmsum_final,
  76. .descsize = CRC_T10DIF_DIGEST_SIZE,
  77. .digestsize = CRC_T10DIF_DIGEST_SIZE,
  78. .base = {
  79. .cra_name = "crct10dif",
  80. .cra_driver_name = "crct10dif-vpmsum",
  81. .cra_priority = 200,
  82. .cra_blocksize = CRC_T10DIF_BLOCK_SIZE,
  83. .cra_module = THIS_MODULE,
  84. }
  85. };
  86. static int __init crct10dif_vpmsum_mod_init(void)
  87. {
  88. if (!cpu_has_feature(CPU_FTR_ARCH_207S))
  89. return -ENODEV;
  90. return crypto_register_shash(&alg);
  91. }
  92. static void __exit crct10dif_vpmsum_mod_fini(void)
  93. {
  94. crypto_unregister_shash(&alg);
  95. }
  96. module_cpu_feature_match(PPC_MODULE_FEATURE_VEC_CRYPTO, crct10dif_vpmsum_mod_init);
  97. module_exit(crct10dif_vpmsum_mod_fini);
  98. MODULE_AUTHOR("Daniel Axtens <[email protected]>");
  99. MODULE_DESCRIPTION("CRCT10DIF using vector polynomial multiply-sum instructions");
  100. MODULE_LICENSE("GPL");
  101. MODULE_ALIAS_CRYPTO("crct10dif");
  102. MODULE_ALIAS_CRYPTO("crct10dif-vpmsum");