1*efd1d2c8SEric Biggers /* SPDX-License-Identifier: GPL-2.0-or-later */ 2*efd1d2c8SEric Biggers /* 3*efd1d2c8SEric Biggers * GHASH optimized using the CP Assist for Cryptographic Functions (CPACF) 4*efd1d2c8SEric Biggers * 5*efd1d2c8SEric Biggers * Copyright 2026 Google LLC 6*efd1d2c8SEric Biggers */ 7*efd1d2c8SEric Biggers #include <asm/cpacf.h> 8*efd1d2c8SEric Biggers #include <linux/cpufeature.h> 9*efd1d2c8SEric Biggers 10*efd1d2c8SEric Biggers static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_cpacf_ghash); 11*efd1d2c8SEric Biggers 12*efd1d2c8SEric Biggers #define ghash_preparekey_arch ghash_preparekey_arch 13*efd1d2c8SEric Biggers static void ghash_preparekey_arch(struct ghash_key *key, 14*efd1d2c8SEric Biggers const u8 raw_key[GHASH_BLOCK_SIZE]) 15*efd1d2c8SEric Biggers { 16*efd1d2c8SEric Biggers /* Save key in POLYVAL format for fallback */ 17*efd1d2c8SEric Biggers ghash_key_to_polyval(raw_key, &key->h); 18*efd1d2c8SEric Biggers 19*efd1d2c8SEric Biggers /* Save key in GHASH format for CPACF_KIMD_GHASH */ 20*efd1d2c8SEric Biggers memcpy(key->h_raw, raw_key, GHASH_BLOCK_SIZE); 21*efd1d2c8SEric Biggers } 22*efd1d2c8SEric Biggers 23*efd1d2c8SEric Biggers #define ghash_blocks_arch ghash_blocks_arch 24*efd1d2c8SEric Biggers static void ghash_blocks_arch(struct polyval_elem *acc, 25*efd1d2c8SEric Biggers const struct ghash_key *key, 26*efd1d2c8SEric Biggers const u8 *data, size_t nblocks) 27*efd1d2c8SEric Biggers { 28*efd1d2c8SEric Biggers if (static_branch_likely(&have_cpacf_ghash)) { 29*efd1d2c8SEric Biggers /* 30*efd1d2c8SEric Biggers * CPACF_KIMD_GHASH requires the accumulator and key in a single 31*efd1d2c8SEric Biggers * buffer, each using the GHASH convention. 32*efd1d2c8SEric Biggers */ 33*efd1d2c8SEric Biggers u8 ctx[2][GHASH_BLOCK_SIZE] __aligned(8); 34*efd1d2c8SEric Biggers 35*efd1d2c8SEric Biggers polyval_acc_to_ghash(acc, ctx[0]); 36*efd1d2c8SEric Biggers memcpy(ctx[1], key->h_raw, GHASH_BLOCK_SIZE); 37*efd1d2c8SEric Biggers 38*efd1d2c8SEric Biggers cpacf_kimd(CPACF_KIMD_GHASH, ctx, data, 39*efd1d2c8SEric Biggers nblocks * GHASH_BLOCK_SIZE); 40*efd1d2c8SEric Biggers 41*efd1d2c8SEric Biggers ghash_acc_to_polyval(ctx[0], acc); 42*efd1d2c8SEric Biggers memzero_explicit(ctx, sizeof(ctx)); 43*efd1d2c8SEric Biggers } else { 44*efd1d2c8SEric Biggers ghash_blocks_generic(acc, &key->h, data, nblocks); 45*efd1d2c8SEric Biggers } 46*efd1d2c8SEric Biggers } 47*efd1d2c8SEric Biggers 48*efd1d2c8SEric Biggers #define gf128hash_mod_init_arch gf128hash_mod_init_arch 49*efd1d2c8SEric Biggers static void gf128hash_mod_init_arch(void) 50*efd1d2c8SEric Biggers { 51*efd1d2c8SEric Biggers if (cpu_have_feature(S390_CPU_FEATURE_MSA) && 52*efd1d2c8SEric Biggers cpacf_query_func(CPACF_KIMD, CPACF_KIMD_GHASH)) 53*efd1d2c8SEric Biggers static_branch_enable(&have_cpacf_ghash); 54*efd1d2c8SEric Biggers } 55