crc32-vx.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. * Crypto-API module for CRC-32 algorithms implemented with the
  3. * z/Architecture Vector Extension Facility.
  4. *
  5. * Copyright IBM Corp. 2015
  6. * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  7. */
  8. #define KMSG_COMPONENT "crc32-vx"
  9. #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  10. #include <linux/module.h>
  11. #include <linux/cpufeature.h>
  12. #include <linux/crc32.h>
  13. #include <crypto/internal/hash.h>
  14. #include <asm/fpu/api.h>
  15. #define CRC32_BLOCK_SIZE 1
  16. #define CRC32_DIGEST_SIZE 4
  17. #define VX_MIN_LEN 64
  18. #define VX_ALIGNMENT 16L
  19. #define VX_ALIGN_MASK (VX_ALIGNMENT - 1)
  20. struct crc_ctx {
  21. u32 key;
  22. };
  23. struct crc_desc_ctx {
  24. u32 crc;
  25. };
  26. /* Prototypes for functions in assembly files */
  27. u32 crc32_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
  28. u32 crc32_be_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
  29. u32 crc32c_le_vgfm_16(u32 crc, unsigned char const *buf, size_t size);
  30. /*
  31. * DEFINE_CRC32_VX() - Define a CRC-32 function using the vector extension
  32. *
  33. * Creates a function to perform a particular CRC-32 computation. Depending
  34. * on the message buffer, the hardware-accelerated or software implementation
  35. * is used. Note that the message buffer is aligned to improve fetch
  36. * operations of VECTOR LOAD MULTIPLE instructions.
  37. *
  38. */
  39. #define DEFINE_CRC32_VX(___fname, ___crc32_vx, ___crc32_sw) \
  40. static u32 __pure ___fname(u32 crc, \
  41. unsigned char const *data, size_t datalen) \
  42. { \
  43. struct kernel_fpu vxstate; \
  44. unsigned long prealign, aligned, remaining; \
  45. \
  46. if (datalen < VX_MIN_LEN + VX_ALIGN_MASK) \
  47. return ___crc32_sw(crc, data, datalen); \
  48. \
  49. if ((unsigned long)data & VX_ALIGN_MASK) { \
  50. prealign = VX_ALIGNMENT - \
  51. ((unsigned long)data & VX_ALIGN_MASK); \
  52. datalen -= prealign; \
  53. crc = ___crc32_sw(crc, data, prealign); \
  54. data = (void *)((unsigned long)data + prealign); \
  55. } \
  56. \
  57. aligned = datalen & ~VX_ALIGN_MASK; \
  58. remaining = datalen & VX_ALIGN_MASK; \
  59. \
  60. kernel_fpu_begin(&vxstate, KERNEL_VXR_LOW); \
  61. crc = ___crc32_vx(crc, data, aligned); \
  62. kernel_fpu_end(&vxstate, KERNEL_VXR_LOW); \
  63. \
  64. if (remaining) \
  65. crc = ___crc32_sw(crc, data + aligned, remaining); \
  66. \
  67. return crc; \
  68. }
  69. DEFINE_CRC32_VX(crc32_le_vx, crc32_le_vgfm_16, crc32_le)
  70. DEFINE_CRC32_VX(crc32_be_vx, crc32_be_vgfm_16, crc32_be)
  71. DEFINE_CRC32_VX(crc32c_le_vx, crc32c_le_vgfm_16, __crc32c_le)
  72. static int crc32_vx_cra_init_zero(struct crypto_tfm *tfm)
  73. {
  74. struct crc_ctx *mctx = crypto_tfm_ctx(tfm);
  75. mctx->key = 0;
  76. return 0;
  77. }
  78. static int crc32_vx_cra_init_invert(struct crypto_tfm *tfm)
  79. {
  80. struct crc_ctx *mctx = crypto_tfm_ctx(tfm);
  81. mctx->key = ~0;
  82. return 0;
  83. }
  84. static int crc32_vx_init(struct shash_desc *desc)
  85. {
  86. struct crc_ctx *mctx = crypto_shash_ctx(desc->tfm);
  87. struct crc_desc_ctx *ctx = shash_desc_ctx(desc);
  88. ctx->crc = mctx->key;
  89. return 0;
  90. }
  91. static int crc32_vx_setkey(struct crypto_shash *tfm, const u8 *newkey,
  92. unsigned int newkeylen)
  93. {
  94. struct crc_ctx *mctx = crypto_shash_ctx(tfm);
  95. if (newkeylen != sizeof(mctx->key)) {
  96. crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
  97. return -EINVAL;
  98. }
  99. mctx->key = le32_to_cpu(*(__le32 *)newkey);
  100. return 0;
  101. }
  102. static int crc32be_vx_setkey(struct crypto_shash *tfm, const u8 *newkey,
  103. unsigned int newkeylen)
  104. {
  105. struct crc_ctx *mctx = crypto_shash_ctx(tfm);
  106. if (newkeylen != sizeof(mctx->key)) {
  107. crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
  108. return -EINVAL;
  109. }
  110. mctx->key = be32_to_cpu(*(__be32 *)newkey);
  111. return 0;
  112. }
  113. static int crc32le_vx_final(struct shash_desc *desc, u8 *out)
  114. {
  115. struct crc_desc_ctx *ctx = shash_desc_ctx(desc);
  116. *(__le32 *)out = cpu_to_le32p(&ctx->crc);
  117. return 0;
  118. }
  119. static int crc32be_vx_final(struct shash_desc *desc, u8 *out)
  120. {
  121. struct crc_desc_ctx *ctx = shash_desc_ctx(desc);
  122. *(__be32 *)out = cpu_to_be32p(&ctx->crc);
  123. return 0;
  124. }
  125. static int crc32c_vx_final(struct shash_desc *desc, u8 *out)
  126. {
  127. struct crc_desc_ctx *ctx = shash_desc_ctx(desc);
  128. /*
  129. * Perform a final XOR with 0xFFFFFFFF to be in sync
  130. * with the generic crc32c shash implementation.
  131. */
  132. *(__le32 *)out = ~cpu_to_le32p(&ctx->crc);
  133. return 0;
  134. }
  135. static int __crc32le_vx_finup(u32 *crc, const u8 *data, unsigned int len,
  136. u8 *out)
  137. {
  138. *(__le32 *)out = cpu_to_le32(crc32_le_vx(*crc, data, len));
  139. return 0;
  140. }
  141. static int __crc32be_vx_finup(u32 *crc, const u8 *data, unsigned int len,
  142. u8 *out)
  143. {
  144. *(__be32 *)out = cpu_to_be32(crc32_be_vx(*crc, data, len));
  145. return 0;
  146. }
  147. static int __crc32c_vx_finup(u32 *crc, const u8 *data, unsigned int len,
  148. u8 *out)
  149. {
  150. /*
  151. * Perform a final XOR with 0xFFFFFFFF to be in sync
  152. * with the generic crc32c shash implementation.
  153. */
  154. *(__le32 *)out = ~cpu_to_le32(crc32c_le_vx(*crc, data, len));
  155. return 0;
  156. }
  157. #define CRC32_VX_FINUP(alg, func) \
  158. static int alg ## _vx_finup(struct shash_desc *desc, const u8 *data, \
  159. unsigned int datalen, u8 *out) \
  160. { \
  161. return __ ## alg ## _vx_finup(shash_desc_ctx(desc), \
  162. data, datalen, out); \
  163. }
  164. CRC32_VX_FINUP(crc32le, crc32_le_vx)
  165. CRC32_VX_FINUP(crc32be, crc32_be_vx)
  166. CRC32_VX_FINUP(crc32c, crc32c_le_vx)
  167. #define CRC32_VX_DIGEST(alg, func) \
  168. static int alg ## _vx_digest(struct shash_desc *desc, const u8 *data, \
  169. unsigned int len, u8 *out) \
  170. { \
  171. return __ ## alg ## _vx_finup(crypto_shash_ctx(desc->tfm), \
  172. data, len, out); \
  173. }
  174. CRC32_VX_DIGEST(crc32le, crc32_le_vx)
  175. CRC32_VX_DIGEST(crc32be, crc32_be_vx)
  176. CRC32_VX_DIGEST(crc32c, crc32c_le_vx)
  177. #define CRC32_VX_UPDATE(alg, func) \
  178. static int alg ## _vx_update(struct shash_desc *desc, const u8 *data, \
  179. unsigned int datalen) \
  180. { \
  181. struct crc_desc_ctx *ctx = shash_desc_ctx(desc); \
  182. ctx->crc = func(ctx->crc, data, datalen); \
  183. return 0; \
  184. }
  185. CRC32_VX_UPDATE(crc32le, crc32_le_vx)
  186. CRC32_VX_UPDATE(crc32be, crc32_be_vx)
  187. CRC32_VX_UPDATE(crc32c, crc32c_le_vx)
  188. static struct shash_alg crc32_vx_algs[] = {
  189. /* CRC-32 LE */
  190. {
  191. .init = crc32_vx_init,
  192. .setkey = crc32_vx_setkey,
  193. .update = crc32le_vx_update,
  194. .final = crc32le_vx_final,
  195. .finup = crc32le_vx_finup,
  196. .digest = crc32le_vx_digest,
  197. .descsize = sizeof(struct crc_desc_ctx),
  198. .digestsize = CRC32_DIGEST_SIZE,
  199. .base = {
  200. .cra_name = "crc32",
  201. .cra_driver_name = "crc32-vx",
  202. .cra_priority = 200,
  203. .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
  204. .cra_blocksize = CRC32_BLOCK_SIZE,
  205. .cra_ctxsize = sizeof(struct crc_ctx),
  206. .cra_module = THIS_MODULE,
  207. .cra_init = crc32_vx_cra_init_zero,
  208. },
  209. },
  210. /* CRC-32 BE */
  211. {
  212. .init = crc32_vx_init,
  213. .setkey = crc32be_vx_setkey,
  214. .update = crc32be_vx_update,
  215. .final = crc32be_vx_final,
  216. .finup = crc32be_vx_finup,
  217. .digest = crc32be_vx_digest,
  218. .descsize = sizeof(struct crc_desc_ctx),
  219. .digestsize = CRC32_DIGEST_SIZE,
  220. .base = {
  221. .cra_name = "crc32be",
  222. .cra_driver_name = "crc32be-vx",
  223. .cra_priority = 200,
  224. .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
  225. .cra_blocksize = CRC32_BLOCK_SIZE,
  226. .cra_ctxsize = sizeof(struct crc_ctx),
  227. .cra_module = THIS_MODULE,
  228. .cra_init = crc32_vx_cra_init_zero,
  229. },
  230. },
  231. /* CRC-32C LE */
  232. {
  233. .init = crc32_vx_init,
  234. .setkey = crc32_vx_setkey,
  235. .update = crc32c_vx_update,
  236. .final = crc32c_vx_final,
  237. .finup = crc32c_vx_finup,
  238. .digest = crc32c_vx_digest,
  239. .descsize = sizeof(struct crc_desc_ctx),
  240. .digestsize = CRC32_DIGEST_SIZE,
  241. .base = {
  242. .cra_name = "crc32c",
  243. .cra_driver_name = "crc32c-vx",
  244. .cra_priority = 200,
  245. .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
  246. .cra_blocksize = CRC32_BLOCK_SIZE,
  247. .cra_ctxsize = sizeof(struct crc_ctx),
  248. .cra_module = THIS_MODULE,
  249. .cra_init = crc32_vx_cra_init_invert,
  250. },
  251. },
  252. };
  253. static int __init crc_vx_mod_init(void)
  254. {
  255. return crypto_register_shashes(crc32_vx_algs,
  256. ARRAY_SIZE(crc32_vx_algs));
  257. }
  258. static void __exit crc_vx_mod_exit(void)
  259. {
  260. crypto_unregister_shashes(crc32_vx_algs, ARRAY_SIZE(crc32_vx_algs));
  261. }
  262. module_cpu_feature_match(VXRS, crc_vx_mod_init);
  263. module_exit(crc_vx_mod_exit);
  264. MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>");
  265. MODULE_LICENSE("GPL");
  266. MODULE_ALIAS_CRYPTO("crc32");
  267. MODULE_ALIAS_CRYPTO("crc32-vx");
  268. MODULE_ALIAS_CRYPTO("crc32c");
  269. MODULE_ALIAS_CRYPTO("crc32c-vx");