From: Itai Handler <itai.handler@gmail.com>
To: broonie@kernel.org
Cc: linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-spi@vger.kernel.org,
michal.simek@amd.com, Itai Handler <itai.handler@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH v2] spi: spi-zynqmp-gqspi: stop the controller on shutdown
Date: Thu, 10 Sep 2026 20:48:32 +0300 [thread overview]
Message-ID: <20260910174832.873352-1-itai.handler@gmail.com> (raw)
The driver has no ->shutdown, and platform_drv_shutdown() has no
fallback of its own. Unlike pci_device_shutdown(), which clears bus
mastering when kexec_in_progress, nothing on the platform bus disarms a
device that can still write to memory. The normal kexec path never
calls ->suspend either, so the quiesce in zynqmp_qspi_suspend() is not
reached.
A controller that is still executing a DMA read may therefore keep
writing to memory across a kexec. QSPIDMA_DST_ADDR still points at
memory owned by the kernel that called kexec, DST_SIZE is non-zero and
the flash is still clocked, so data can keep landing in RAM while the
new kernel is being relocated, and after it has started executing.
That destination is a physical address which means nothing to the new
kernel, so the writes can corrupt whatever now occupies it: kernel text
or data, page tables, or the initrd. Nothing reports an error and the
resulting behaviour is undefined.
This can be observed by reading GQSPI_EN (offset 0x114) and
QSPIDMA_DST_ADDR/SIZE/STS/CTRL (offsets 0x800 to 0x80c) early in the new
kernel, before the driver probes: without this patch GQSPI_EN reads 1
and QSPIDMA_DST_ADDR still points into the previous kernel's memory.
Add a ->shutdown that stops the controller the way zynqmp_qspi_suspend()
already does. spi_controller_suspend() stops the queue, waits for a
message that is already executing and makes any later transfer fail with
-ESHUTDOWN, so nothing can be cut short by the register write that
follows. It may sleep, which is fine here: device_shutdown() runs in
process context. Unlike ->suspend this cannot abort on error, because a
controller left mastering the bus is worse than a truncated transfer, so
a failure to drain is only logged.
GQSPI_EN_OFST is then cleared, as zynqmp_qspi_remove() and
zynqmp_qspi_suspend() already do. Skip that write only when
pm_runtime_get_if_in_use() returns 0, i.e. runtime suspended: the clocks
are gated, so the registers are unreachable and the controller cannot be
mastering the bus. A negative return is not the same thing - it is what
the CONFIG_PM=n stub always returns, and there probe() has enabled pclk
and refclk for good, so the controller is running and must be stopped.
Fixes: dfe11a11d523 ("spi: Add support for Zynq Ultrascale+ MPSoC GQSPI controller")
Cc: stable@vger.kernel.org
Signed-off-by: Itai Handler <itai.handler@gmail.com>
---
Changes in v2:
- Quiesce through spi_controller_suspend() before touching the hardware,
so nothing can start a new transfer and a message that is already
executing is waited for (Mark Brown).
Note for stable: before commit 1c26372e5aa9 ("spi: spi-zynqmp-gqspi:
Update driver to use spi-mem framework") this driver stored the
spi_master in the platform drvdata rather than the zynqmp_qspi, so a
backport to those trees needs spi_master_get_devdata() in place of the
platform_get_drvdata() used here.
drivers/spi/spi-zynqmp-gqspi.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
index 4d55090..15e9d3e 100644
--- a/drivers/spi/spi-zynqmp-gqspi.c
+++ b/drivers/spi/spi-zynqmp-gqspi.c
@@ -1373,11 +1373,45 @@ static void zynqmp_qspi_remove(struct platform_device *pdev)
clk_disable_unprepare(xqspi->pclk);
}
+static void zynqmp_qspi_shutdown(struct platform_device *pdev)
+{
+ struct zynqmp_qspi *xqspi = platform_get_drvdata(pdev);
+ int ret;
+
+ /*
+ * Stop the queue and reject any later transfer first, so the write
+ * below cannot cut into a message that is still being executed.
+ * Unlike ->suspend this cannot abort on error: a controller left
+ * mastering the bus is worse than a truncated transfer.
+ */
+ ret = spi_controller_suspend(xqspi->ctlr);
+ if (ret)
+ dev_warn(&pdev->dev, "could not stop the queue: %d\n", ret);
+
+ /*
+ * Only a runtime suspended controller can be left alone: its clocks
+ * are gated, so it cannot be mastering the bus, and its registers
+ * must not be accessed either. Any other answer means it may be
+ * running and has to be stopped. In particular, on a kernel built
+ * without runtime PM this returns -EINVAL, and there the clocks
+ * enabled in probe() are never gated at all.
+ */
+ ret = pm_runtime_get_if_in_use(&pdev->dev);
+ if (!ret)
+ return;
+
+ zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0);
+
+ if (ret > 0)
+ pm_runtime_put_noidle(&pdev->dev);
+}
+
MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match);
static struct platform_driver zynqmp_qspi_driver = {
.probe = zynqmp_qspi_probe,
.remove = zynqmp_qspi_remove,
+ .shutdown = zynqmp_qspi_shutdown,
.driver = {
.name = "zynqmp-qspi",
.of_match_table = zynqmp_qspi_of_match,
--
2.34.1
reply other threads:[~2026-09-10 17:49 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260910174832.873352-1-itai.handler@gmail.com \
--to=itai.handler@gmail.com \
--cc=broonie@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-spi@vger.kernel.org \
--cc=michal.simek@amd.com \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.