summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPufan Jin <cyan2254650260@gmail.com>2026-10-16 21:08:12 +0800
committerMark Brown <broonie@kernel.org>2026-10-23 18:46:26 +0100
commitdc5ca34f5e8dc10c566ef39aa3b1a201a17ca734 (patch)
treeda18bd63c4a5fb8d7b07e6f2bc2fbf12ac4d37ac
parentd5acef12e819c1627c8bf6a0325845ab39d8c99d (diff)
spi: zynq-qspi: fix address buffer corruption and support 4-byte address
In zynq_qspi_exec_mem_op(), when transmitting address bytes, the driver iterates over op->addr.nbytes and populates xqspi->txbuf[i]. However, xqspi->txbuf is never re-assigned before populating the address, meaning it still points to (u8 *)&op->cmd.opcode from the command phase. This causes two severe issues: 1. Memory corruption: Writing into xqspi->txbuf writes past the opcode buffer on the stack (which was passed as const struct spi_mem_op *). If opcode is zero, xqspi->txbuf is uninitialized. 2. In zynq_qspi_supports_op(), operations with op->addr.nbytes > 3 are rejected. When paired with SPI NOR flashes larger than 16MB (such as Winbond W25Q256), spi_nor_spimem_check_read_pp_op() tests 4-byte address support, which fails and causes spi_nor_select_read() to drop all read capabilities, failing probe with -EINVAL (-22). The Zynq-7000 QSPI controller hardware in manual I/O mode natively supports transmitting 1 to 4 address bytes via its TXD FIFO registers (ZYNQ_QSPI_TXD_00_00_OFFSET). Fix this by introducing a local opaddr[4] buffer in zynq_qspi_exec_mem_op() and explicitly setting xqspi->txbuf = opaddr before populating address bytes. Also allow up to 4 address bytes in zynq_qspi_supports_op(). Fixes: 67dca5e580f1 ("spi: spi-mem: Add support for Zynq QSPI controller") Cc: stable@vger.kernel.org Signed-off-by: Pufan Jin <cyan2254650260@gmail.com> Link: https://patch.msgid.link/20261016130812.282624-1-cyan2254650260@gmail.com Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/spi/spi-zynq-qspi.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c
index d762aaf452af..bfcbcfe85b91 100644
--- a/drivers/spi/spi-zynq-qspi.c
+++ b/drivers/spi/spi-zynq-qspi.c
@@ -229,11 +229,10 @@ static bool zynq_qspi_supports_op(struct spi_mem *mem,
return false;
/*
- * The number of address bytes should be equal to or less than 3 bytes.
+ * The number of address bytes should be equal to or less than 4 bytes.
*/
- if (op->addr.nbytes > 3)
+ if (op->addr.nbytes > 4)
return false;
-
return true;
}
@@ -526,6 +525,7 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->controller);
+ u8 opaddr[4] __aligned(4);
int err = 0, i;
u8 *tmpbuf;
@@ -547,12 +547,13 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem,
}
if (op->addr.nbytes) {
- for (i = 0; i < op->addr.nbytes; i++) {
- xqspi->txbuf[i] = op->addr.val >>
+ for (i = 0; i < op->addr.nbytes; i++)
+ opaddr[i] = op->addr.val >>
(8 * (op->addr.nbytes - i - 1));
- }
reinit_completion(&xqspi->data_completion);
+ xqspi->txbuf = opaddr;
+
xqspi->rxbuf = NULL;
xqspi->tx_bytes = op->addr.nbytes;
xqspi->rx_bytes = op->addr.nbytes;