From: Boris Brezillon boris.brezillon@bootlin.com
commit 380583227c0c7f52383b0cd5c0e2de93ed31d553 upstream
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 Cc: stable stable@vger.kernel.org # 4.19 Signed-off-by: Mathieu Poirier mathieu.poirier@linaro.org --- drivers/spi/spi-mem.c | 54 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-)
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) {