Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: stm32/crc32 - Avoid lock if hardware is already used

If STM32 CRC device is already in use, calculate CRC by software.

This will release CPU constraint for a concurrent access to the
hardware, and avoid masking irqs during the whole block processing.

Fixes: 7795c0baf5ac ("crypto: stm32/crc32 - protect from concurrent accesses")

Signed-off-by: Nicolas Toromanoff <nicolas.toromanoff@st.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Nicolas Toromanoff and committed by
Herbert Xu
bbf2cb1e c4c75fcb

+13 -3
+1
drivers/crypto/stm32/Kconfig
··· 3 3 tristate "Support for STM32 crc accelerators" 4 4 depends on ARCH_STM32 5 5 select CRYPTO_HASH 6 + select CRC32 6 7 help 7 8 This enables support for the CRC32 hw accelerator which can be found 8 9 on STMicroelectronics STM32 SOC.
+12 -3
drivers/crypto/stm32/stm32-crc32.c
··· 6 6 7 7 #include <linux/bitrev.h> 8 8 #include <linux/clk.h> 9 + #include <linux/crc32.h> 9 10 #include <linux/crc32poly.h> 10 11 #include <linux/io.h> 11 12 #include <linux/kernel.h> ··· 150 149 struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); 151 150 struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); 152 151 struct stm32_crc *crc; 153 - unsigned long flags; 154 152 155 153 crc = stm32_crc_get_next_crc(); 156 154 if (!crc) ··· 157 157 158 158 pm_runtime_get_sync(crc->dev); 159 159 160 - spin_lock_irqsave(&crc->lock, flags); 160 + if (!spin_trylock(&crc->lock)) { 161 + /* Hardware is busy, calculate crc32 by software */ 162 + if (mctx->poly == CRC32_POLY_LE) 163 + ctx->partial = crc32_le(ctx->partial, d8, length); 164 + else 165 + ctx->partial = __crc32c_le(ctx->partial, d8, length); 166 + 167 + goto pm_out; 168 + } 161 169 162 170 /* 163 171 * Restore previously calculated CRC for this context as init value ··· 205 197 /* Store partial result */ 206 198 ctx->partial = readl_relaxed(crc->regs + CRC_DR); 207 199 208 - spin_unlock_irqrestore(&crc->lock, flags); 200 + spin_unlock(&crc->lock); 209 201 202 + pm_out: 210 203 pm_runtime_mark_last_busy(crc->dev); 211 204 pm_runtime_put_autosuspend(crc->dev); 212 205