diff options
| author | Mikhail Kshevetskiy <[email protected]> | 2025-11-01 09:24:24 +0300 |
|---|---|---|
| committer | Michael Trimarchi <[email protected]> | 2025-11-18 20:07:41 +0100 |
| commit | c3c758c20d3560639bfad6ac367f1a13278d67ca (patch) | |
| tree | 5d38793f4b6c403d19caf416a5c0eb7b08791484 /drivers | |
| parent | c675162bcb32360a45fee7a9ba9588241916549b (diff) | |
spi: spi-mem: fix coverity report CID 537478
Coverity finds a potential integer overflow in the following code:
ncycles += ((op->data.nbytes * 8) / op->data.buswidth) / (op->data.dtr ? 2 : 1);
A quick analysis shows that the only caller of the suspicious code is the
spinand_select_op_variant() function from the drivers/mtd/nand/spi/core.c
file.
According to the code the value of op->data.nbytes is equal to
nanddev_per_page_oobsize(nand) + nanddev_page_size(nand)
Therefore it's maximum value a bit larger than 4Kb (I never seen flashes
with page size large than 4Kb). So op->data.nbytes always fits within
13 bits. As result an overflow will never happen.
Anyway it's better fix an issue to eliminate the error message.
Signed-off-by: Mikhail Kshevetskiy <[email protected]>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/spi/spi-mem.c | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index db44a7b26eb..3fd2353af94 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -499,6 +499,31 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op) } EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); +static inline u64 spi_mem_bytes_to_ncycles(u32 nbytes, u8 buswidth, u8 dtr) +{ + u64 ncycles; + u32 divider = buswidth * (dtr ? 2 : 1); + + /* + * Theoretically + * + * ncycles = (nbytes * 8) / (buswidth * (dtr ? 2 : 1)); + * + * may lead to an integer overflow, if nbytes will be larger than + * 0x1fffffff. Lets split this operation on: + * + * 1) Operation with bits 0..28 (overflow will not happen), + * + * 2) Operation with bits 29..31. Here we'll take into account + * that buswidth is a small power of 2 (so whole divider is + * small power of 2). Hense we may divide first, then multiply. + */ + ncycles = ((nbytes & 0x1fffffff) * 8) / divider; + ncycles += ((u64) ((nbytes & ~0x1fffffff) / divider)) * 8; + + return ncycles; +} + /** * spi_mem_calc_op_duration() - Derives the theoretical length (in cpu cycles) * of an operation. This helps finding the best @@ -518,14 +543,22 @@ u64 spi_mem_calc_op_duration(struct spi_mem_op *op) { u64 ncycles = 0; - ncycles += ((op->cmd.nbytes * 8) / op->cmd.buswidth) / (op->cmd.dtr ? 2 : 1); - ncycles += ((op->addr.nbytes * 8) / op->addr.buswidth) / (op->addr.dtr ? 2 : 1); + ncycles += spi_mem_bytes_to_ncycles(op->cmd.nbytes, + op->cmd.buswidth, + op->cmd.dtr); + ncycles += spi_mem_bytes_to_ncycles(op->addr.nbytes, + op->addr.buswidth, + op->addr.dtr); /* Dummy bytes are optional for some SPI flash memory operations */ if (op->dummy.nbytes) - ncycles += ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1); + ncycles += spi_mem_bytes_to_ncycles(op->dummy.nbytes, + op->dummy.buswidth, + op->dummy.dtr); - ncycles += ((op->data.nbytes * 8) / op->data.buswidth) / (op->data.dtr ? 2 : 1); + ncycles += spi_mem_bytes_to_ncycles(op->data.nbytes, + op->data.buswidth, + op->data.dtr); return ncycles; } |
