polyval.h 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. /* SPDX-License-Identifier: GPL-2.0-or-later */
  2. /*
  3. * POLYVAL library functions, x86_64 optimized
  4. *
  5. * Copyright 2025 Google LLC
  6. */
  7. #include <asm/fpu/api.h>
  8. #include <linux/cpufeature.h>
  9. #define NUM_H_POWERS 8
  10. static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_pclmul_avx);
  11. asmlinkage void polyval_mul_pclmul_avx(struct polyval_elem *a,
  12. const struct polyval_elem *b);
  13. asmlinkage void polyval_blocks_pclmul_avx(struct polyval_elem *acc,
  14. const struct polyval_key *key,
  15. const u8 *data, size_t nblocks);
  16. static void polyval_preparekey_arch(struct polyval_key *key,
  17. const u8 raw_key[POLYVAL_BLOCK_SIZE])
  18. {
  19. static_assert(ARRAY_SIZE(key->h_powers) == NUM_H_POWERS);
  20. memcpy(&key->h_powers[NUM_H_POWERS - 1], raw_key, POLYVAL_BLOCK_SIZE);
  21. if (static_branch_likely(&have_pclmul_avx) && irq_fpu_usable()) {
  22. kernel_fpu_begin();
  23. for (int i = NUM_H_POWERS - 2; i >= 0; i--) {
  24. key->h_powers[i] = key->h_powers[i + 1];
  25. polyval_mul_pclmul_avx(
  26. &key->h_powers[i],
  27. &key->h_powers[NUM_H_POWERS - 1]);
  28. }
  29. kernel_fpu_end();
  30. } else {
  31. for (int i = NUM_H_POWERS - 2; i >= 0; i--) {
  32. key->h_powers[i] = key->h_powers[i + 1];
  33. polyval_mul_generic(&key->h_powers[i],
  34. &key->h_powers[NUM_H_POWERS - 1]);
  35. }
  36. }
  37. }
  38. static void polyval_mul_arch(struct polyval_elem *acc,
  39. const struct polyval_key *key)
  40. {
  41. if (static_branch_likely(&have_pclmul_avx) && irq_fpu_usable()) {
  42. kernel_fpu_begin();
  43. polyval_mul_pclmul_avx(acc, &key->h_powers[NUM_H_POWERS - 1]);
  44. kernel_fpu_end();
  45. } else {
  46. polyval_mul_generic(acc, &key->h_powers[NUM_H_POWERS - 1]);
  47. }
  48. }
  49. static void polyval_blocks_arch(struct polyval_elem *acc,
  50. const struct polyval_key *key,
  51. const u8 *data, size_t nblocks)
  52. {
  53. if (static_branch_likely(&have_pclmul_avx) && irq_fpu_usable()) {
  54. do {
  55. /* Allow rescheduling every 4 KiB. */
  56. size_t n = min_t(size_t, nblocks,
  57. 4096 / POLYVAL_BLOCK_SIZE);
  58. kernel_fpu_begin();
  59. polyval_blocks_pclmul_avx(acc, key, data, n);
  60. kernel_fpu_end();
  61. data += n * POLYVAL_BLOCK_SIZE;
  62. nblocks -= n;
  63. } while (nblocks);
  64. } else {
  65. polyval_blocks_generic(acc, &key->h_powers[NUM_H_POWERS - 1],
  66. data, nblocks);
  67. }
  68. }
  69. #define polyval_mod_init_arch polyval_mod_init_arch
  70. static void polyval_mod_init_arch(void)
  71. {
  72. if (boot_cpu_has(X86_FEATURE_PCLMULQDQ) &&
  73. boot_cpu_has(X86_FEATURE_AVX))
  74. static_branch_enable(&have_pclmul_avx);
  75. }