spi: spi-mem: Add extra sanity checks on the op param
authorBoris Brezillon <boris.brezillon@bootlin.com>
Thu, 20 Sep 2018 07:31:12 +0000 (09:31 +0200)
committerMark Brown <broonie@kernel.org>
Thu, 20 Sep 2018 19:24:00 +0000 (12:24 -0700)
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>
drivers/spi/spi-mem.c

index eb72dba71d832a47165b824c2f859fed00a33a4e..cc3d425aae56c6347b0db551c2c3fed9784f9670 100644 (file)
@@ -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) {