crct10dif-vpmsum_glue.c 3.0 KB

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