@@ -31,8 +31,9 @@
.arch armv8-a+crypto
/*
- * void pmull_ghash_update(int blocks, u64 dg[], const char *src,
- * struct ghash_key const *k, const char *head)
+ * int pmull_ghash_update(int blocks, u64 dg[], const char *src,
+ * struct ghash_key const *k, const char *head,
+ * struct thread_info *ti)
*/
ENTRY(pmull_ghash_update)
ld1 {DATA.16b}, [x1]
@@ -88,8 +89,9 @@ CPU_LE( rev64 IN1.16b, IN1.16b )
eor T1.16b, T1.16b, T2.16b
eor DATA.16b, DATA.16b, T1.16b
- cbnz w0, 0b
+ cbz w0, 2f
+ b_if_no_resched x5, x7, 0b
- st1 {DATA.16b}, [x1]
+2: st1 {DATA.16b}, [x1]
ret
ENDPROC(pmull_ghash_update)
@@ -33,8 +33,9 @@ struct ghash_desc_ctx {
u32 count;
};
-asmlinkage void pmull_ghash_update(int blocks, u64 dg[], const char *src,
- struct ghash_key const *k, const char *head);
+asmlinkage int pmull_ghash_update(int blocks, u64 dg[], const char *src,
+ struct ghash_key const *k, const char *head,
+ struct thread_info *ti);
static int ghash_init(struct shash_desc *desc)
{
@@ -54,6 +55,7 @@ static int ghash_update(struct shash_desc *desc, const u8 *src,
if ((partial + len) >= GHASH_BLOCK_SIZE) {
struct ghash_key *key = crypto_shash_ctx(desc->tfm);
+ struct thread_info *ti = NULL;
int blocks;
if (partial) {
@@ -64,14 +66,30 @@ static int ghash_update(struct shash_desc *desc, const u8 *src,
len -= p;
}
+ /*
+ * Pass current's thread info pointer to pmull_ghash_update()
+ * below if we want it to play nice under preemption.
+ */
+ if ((IS_ENABLED(CONFIG_PREEMPT_VOLUNTARY) ||
+ IS_ENABLED(CONFIG_PREEMPT))
+ && (desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP))
+ ti = current_thread_info();
+
blocks = len / GHASH_BLOCK_SIZE;
len %= GHASH_BLOCK_SIZE;
- kernel_neon_begin_partial(6);
- pmull_ghash_update(blocks, ctx->digest, src, key,
- partial ? ctx->buf : NULL);
- kernel_neon_end();
- src += blocks * GHASH_BLOCK_SIZE;
+ do {
+ int rem;
+
+ kernel_neon_begin_partial(6);
+ rem = pmull_ghash_update(blocks, ctx->digest, src, key,
+ partial ? ctx->buf : NULL, ti);
+ kernel_neon_end();
+
+ src += (blocks - rem) * GHASH_BLOCK_SIZE;
+ blocks = rem;
+ partial = 0;
+ } while (unlikely(ti && blocks > 0));
}
if (len)
memcpy(ctx->buf + partial, src, len);
@@ -89,7 +107,7 @@ static int ghash_final(struct shash_desc *desc, u8 *dst)
memset(ctx->buf + partial, 0, GHASH_BLOCK_SIZE - partial);
kernel_neon_begin_partial(6);
- pmull_ghash_update(1, ctx->digest, ctx->buf, key, NULL);
+ pmull_ghash_update(1, ctx->digest, ctx->buf, key, NULL, NULL);
kernel_neon_end();
}
put_unaligned_be64(ctx->digest[1], dst);