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:
parent
f34ecdbd56
commit
380583227c
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue