aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2014-06-26 07:43:02 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2014-07-03 09:42:10 -0400
commite1f8859ee265fc89bd21b4dca79e8e983a044892 (patch)
tree018e9e6dc1b60987d39180e5f10605f03a72be6e
parent263a8df0d32eca17693f80f8cde416c9312a2239 (diff)
crypto: ux500 - make interrupt mode plausible
The interrupt handler in the ux500 crypto driver has an obviously incorrect way to access the data buffer, which for a while has caused this build warning: ../ux500/cryp/cryp_core.c: In function 'cryp_interrupt_handler': ../ux500/cryp/cryp_core.c:234:5: warning: passing argument 1 of '__fswab32' makes integer from pointer without a cast [enabled by default] writel_relaxed(ctx->indata, ^ In file included from ../include/linux/swab.h:4:0, from ../include/uapi/linux/byteorder/big_endian.h:12, from ../include/linux/byteorder/big_endian.h:4, from ../arch/arm/include/uapi/asm/byteorder.h:19, from ../include/asm-generic/bitops/le.h:5, from ../arch/arm/include/asm/bitops.h:340, from ../include/linux/bitops.h:33, from ../include/linux/kernel.h:10, from ../include/linux/clk.h:16, from ../drivers/crypto/ux500/cryp/cryp_core.c:12: ../include/uapi/linux/swab.h:57:119: note: expected '__u32' but argument is of type 'const u8 *' static inline __attribute_const__ __u32 __fswab32(__u32 val) There are at least two, possibly three problems here: a) when writing into the FIFO, we copy the pointer rather than the actual data we want to give to the hardware b) the data pointer is an array of 8-bit values, while the FIFO is 32-bit wide, so both the read and write access fail to do a proper type conversion c) This seems incorrect for big-endian kernels, on which we need to byte-swap any register access, but not normally FIFO accesses, at least the DMA case doesn't do it either. This converts the bogus loop to use the same readsl/writesl pair that we use for the two other modes (DMA and polling). This is more efficient and consistent, and probably correct for endianess. The bug has existed since the driver was first merged, and was probably never detected because nobody tried to use interrupt mode. It might make sense to backport this fix to stable kernels, depending on how the crypto maintainers feel about that. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Cc: linux-crypto@vger.kernel.org Cc: Fabio Baltieri <fabio.baltieri@linaro.org> Cc: Linus Walleij <linus.walleij@linaro.org> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: "David S. Miller" <davem@davemloft.net> Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--drivers/crypto/ux500/cryp/cryp_core.c25
1 files changed, 12 insertions, 13 deletions
diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c
index a999f537228f..92105f3dc8e0 100644
--- a/drivers/crypto/ux500/cryp/cryp_core.c
+++ b/drivers/crypto/ux500/cryp/cryp_core.c
@@ -190,7 +190,7 @@ static void add_session_id(struct cryp_ctx *ctx)
190static irqreturn_t cryp_interrupt_handler(int irq, void *param) 190static irqreturn_t cryp_interrupt_handler(int irq, void *param)
191{ 191{
192 struct cryp_ctx *ctx; 192 struct cryp_ctx *ctx;
193 int i; 193 int count;
194 struct cryp_device_data *device_data; 194 struct cryp_device_data *device_data;
195 195
196 if (param == NULL) { 196 if (param == NULL) {
@@ -215,12 +215,11 @@ static irqreturn_t cryp_interrupt_handler(int irq, void *param)
215 if (cryp_pending_irq_src(device_data, 215 if (cryp_pending_irq_src(device_data,
216 CRYP_IRQ_SRC_OUTPUT_FIFO)) { 216 CRYP_IRQ_SRC_OUTPUT_FIFO)) {
217 if (ctx->outlen / ctx->blocksize > 0) { 217 if (ctx->outlen / ctx->blocksize > 0) {
218 for (i = 0; i < ctx->blocksize / 4; i++) { 218 count = ctx->blocksize / 4;
219 *(ctx->outdata) = readl_relaxed( 219
220 &device_data->base->dout); 220 readsl(&device_data->base->dout, ctx->outdata, count);
221 ctx->outdata += 4; 221 ctx->outdata += count;
222 ctx->outlen -= 4; 222 ctx->outlen -= count;
223 }
224 223
225 if (ctx->outlen == 0) { 224 if (ctx->outlen == 0) {
226 cryp_disable_irq_src(device_data, 225 cryp_disable_irq_src(device_data,
@@ -230,12 +229,12 @@ static irqreturn_t cryp_interrupt_handler(int irq, void *param)
230 } else if (cryp_pending_irq_src(device_data, 229 } else if (cryp_pending_irq_src(device_data,
231 CRYP_IRQ_SRC_INPUT_FIFO)) { 230 CRYP_IRQ_SRC_INPUT_FIFO)) {
232 if (ctx->datalen / ctx->blocksize > 0) { 231 if (ctx->datalen / ctx->blocksize > 0) {
233 for (i = 0 ; i < ctx->blocksize / 4; i++) { 232 count = ctx->blocksize / 4;
234 writel_relaxed(ctx->indata, 233
235 &device_data->base->din); 234 writesl(&device_data->base->din, ctx->indata, count);
236 ctx->indata += 4; 235
237 ctx->datalen -= 4; 236 ctx->indata += count;
238 } 237 ctx->datalen -= count;
239 238
240 if (ctx->datalen == 0) 239 if (ctx->datalen == 0)
241 cryp_disable_irq_src(device_data, 240 cryp_disable_irq_src(device_data,