From e757996cafbeb6b71234a17130674bcd8f44c59e Mon Sep 17 00:00:00 2001 From: Chuanhua Han Date: Thu, 30 Aug 2018 16:43:24 +0800 Subject: spi: spi-mem: Adjust op len based on message/transfer size limitations We need that to adjust the len of the 2nd transfer (called data in spi-mem) if it's too long to fit in a SPI message or SPI transfer. Fixes: c36ff266dc82 ("spi: Extend the core to ease integration of SPI memory controllers") Cc: Signed-off-by: Chuanhua Han Reviewed-by: Boris Brezillon Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/spi/spi-mem.c') diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index e43842c7a31a..eb72dba71d83 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -346,10 +346,25 @@ EXPORT_SYMBOL_GPL(spi_mem_get_name); int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) { struct spi_controller *ctlr = mem->spi->controller; + size_t len; + + len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size) return ctlr->mem_ops->adjust_op_size(mem, op); + if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) { + if (len > spi_max_transfer_size(mem->spi)) + return -EINVAL; + + op->data.nbytes = min3((size_t)op->data.nbytes, + spi_max_transfer_size(mem->spi), + spi_max_message_size(mem->spi) - + len); + if (!op->data.nbytes) + return -EINVAL; + } + return 0; } EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); -- cgit v1.2.3-70-g09d2 From 380583227c0c7f52383b0cd5c0e2de93ed31d553 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 20 Sep 2018 09:31:12 +0200 Subject: 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 Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 54 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 6 deletions(-) (limited to 'drivers/spi/spi-mem.c') diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index eb72dba71d83..cc3d425aae56 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -12,6 +12,8 @@ #include "internals.h" +#define SPI_MEM_MAX_BUSWIDTH 4 + /** * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a * 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); +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 * 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) { - struct spi_controller *ctlr = mem->spi->controller; - - if (ctlr->mem_ops && ctlr->mem_ops->supports_op) - return ctlr->mem_ops->supports_op(mem, op); + if (spi_mem_check_op(op)) + return false; - return spi_mem_default_supports_op(mem, op); + return spi_mem_internal_supports_op(mem, 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; 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; if (ctlr->mem_ops) { -- cgit v1.2.3-70-g09d2 From aea3877e24f3acc6145094848dbb85f9ce85674a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Sep 2018 11:46:55 +0200 Subject: spi: spi-mem: Fix inverted logic in op sanity check On r8a7791/koelsch: m25p80 spi0.0: error -22 reading 9f m25p80: probe of spi0.0 failed with error -22 Apparently the logic in spi_mem_check_op() is wrong, rejecting the spi-mem operation if any buswidth is valid, instead of invalid. Fixes: 380583227c0c7f52 ("spi: spi-mem: Add extra sanity checks on the op param") Signed-off-by: Geert Uytterhoeven Reviewed-by: Boris Brezillon Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/spi/spi-mem.c') diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index cc3d425aae56..62a7b80801d2 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -169,10 +169,10 @@ static int spi_mem_check_op(const struct spi_mem_op *op) (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)) + 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; -- cgit v1.2.3-70-g09d2