spi: spi-mem: Add extra sanity checks on the op param

Some combinations are simply not valid and should be rejected before
the op is passed to the SPI controller driver.

Add an spi_mem_check_op() helper and use it in spi_mem_exec_op() and
spi_mem_supports_op() to make sure the spi-mem operation is valid.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Boris Brezillon 2018-09-20 09:31:12 +02:00 committed by Mark Brown
parent f34ecdbd56
commit 380583227c
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
1 changed files with 48 additions and 6 deletions

View File

@ -12,6 +12,8 @@
#include "internals.h" #include "internals.h"
#define SPI_MEM_MAX_BUSWIDTH 4
/** /**
* spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a
* memory operation * memory operation
@ -149,6 +151,44 @@ static bool spi_mem_default_supports_op(struct spi_mem *mem,
} }
EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
static bool spi_mem_buswidth_is_valid(u8 buswidth)
{
if (hweight8(buswidth) > 1 || buswidth > SPI_MEM_MAX_BUSWIDTH)
return false;
return true;
}
static int spi_mem_check_op(const struct spi_mem_op *op)
{
if (!op->cmd.buswidth)
return -EINVAL;
if ((op->addr.nbytes && !op->addr.buswidth) ||
(op->dummy.nbytes && !op->dummy.buswidth) ||
(op->data.nbytes && !op->data.buswidth))
return -EINVAL;
if (spi_mem_buswidth_is_valid(op->cmd.buswidth) ||
spi_mem_buswidth_is_valid(op->addr.buswidth) ||
spi_mem_buswidth_is_valid(op->dummy.buswidth) ||
spi_mem_buswidth_is_valid(op->data.buswidth))
return -EINVAL;
return 0;
}
static bool spi_mem_internal_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct spi_controller *ctlr = mem->spi->controller;
if (ctlr->mem_ops && ctlr->mem_ops->supports_op)
return ctlr->mem_ops->supports_op(mem, op);
return spi_mem_default_supports_op(mem, op);
}
/** /**
* spi_mem_supports_op() - Check if a memory device and the controller it is * spi_mem_supports_op() - Check if a memory device and the controller it is
* connected to support a specific memory operation * connected to support a specific memory operation
@ -166,12 +206,10 @@ EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
*/ */
bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
{ {
struct spi_controller *ctlr = mem->spi->controller; if (spi_mem_check_op(op))
return false;
if (ctlr->mem_ops && ctlr->mem_ops->supports_op) return spi_mem_internal_supports_op(mem, op);
return ctlr->mem_ops->supports_op(mem, op);
return spi_mem_default_supports_op(mem, op);
} }
EXPORT_SYMBOL_GPL(spi_mem_supports_op); EXPORT_SYMBOL_GPL(spi_mem_supports_op);
@ -196,7 +234,11 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
u8 *tmpbuf; u8 *tmpbuf;
int ret; int ret;
if (!spi_mem_supports_op(mem, op)) ret = spi_mem_check_op(op);
if (ret)
return ret;
if (!spi_mem_internal_supports_op(mem, op))
return -ENOTSUPP; return -ENOTSUPP;
if (ctlr->mem_ops) { if (ctlr->mem_ops) {