* [PATCH AUTOSEL 6.18-6.12] spi: dw-mmio: Add ACPI ID LECA0002 for LECARC SoCs
[not found] <20260831133314.4125787-1-sashal@kernel.org>
@ 2026-08-31 13:20 ` Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18-5.15] spi: Add NULL check for spi_get_device_id() in spi_get_device_match_data() Sasha Levin
` (8 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2026-08-31 13:20 UTC (permalink / raw)
To: patches, stable
Cc: Thomas Lin, Andy Shevchenko, Mark Brown, Sasha Levin, rafael,
linux-acpi, linux-kernel, linux-spi
From: Thomas Lin <thomas_lin@lecomputing.com>
[ Upstream commit 019947c495850461242fdcc0780258805595036c ]
This ID requires a custom initialization function
dw_spi_hssi_no_dma_init() that sets dws->dws.ip to DW_HSSI_ID.
Signed-off-by: Thomas Lin <thomas_lin@lecomputing.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://patch.msgid.link/20260521-lecarc-acpi-ids-v1-2-ae0ae90b2817@lecomputing.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
Connection lost, reconnecting to https://agentn.us.api5.cursor.sh
(attempt 1)...
Retry attempt 1...
# Stable Backport Analysis: `spi: dw-mmio: Add ACPI ID LECA0002 for
LECARC SoCs`
**Local tree:** `v6.18.44` (`stable/linux-6.18.y`, detached HEAD at
`1efe5d048a391`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[spi: dw-mmio]` `[Add]` — Add ACPI ID `LECA0002` for LECARC
SoCs SPI controller enablement on ACPI/ARM64 platforms.
### Step 1.2: Tags
**Record:**
- **Signed-off-by:** Thomas Lin \<thomas_lin@lecomputing.com\> (author)
- **Reviewed-by:** Andy Shevchenko \<andriy.shevchenko@linux.intel.com\>
- **Link:** https://patch.msgid.link/20260521-lecarc-acpi-
ids-v1-2-ae0ae90b2817@lecomputing.com
- **Signed-off-by:** Mark Brown \<broonie@kernel.org\> (SPI maintainer
merge tag in final commit)
- **Acked-by:** Mark Brown (in v1 mbox submission)
- No Fixes:, Reported-by:, Tested-by:, Cc: stable@
- Notable: subsystem maintainer ack; no syzbot/user bug reports
### Step 1.3: Body text
**Record:**
- **Bug description:** LECARC SoCs expose SPI via ACPI HID `LECA0002`;
without this ID the existing `dw_spi_mmio` driver does not bind.
- **Symptom:** SPI controller non-functional on LECARC ACPI boots (no
driver probe).
- **Root cause:** Missing ACPI ID in `acpi_apd.c` (clock/platform device
creation) and `spi-dw-mmio.c` (driver match + HSSI init).
- **Init requirement:** Must use `dw_spi_hssi_no_dma_init()` to set
`dws->ip = DW_HSSI_ID` (HSSI register layout, no DMA).
- **Version info:** None explicit; part of v5 series dated 2026-05-21.
### Step 1.4: Hidden bug fix?
**Record:** No — this is hardware enablement (ACPI ID addition), not a
regression fix. The function rename (`dw_spi_intel_init` →
`dw_spi_hssi_no_dma_init`) is cosmetic; behavior is unchanged. Without
the ACPI entry, hardware simply does not probe; there is no pre-existing
broken path for current 6.18.y users.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
| File | Changes |
|------|---------|
| `drivers/acpi/acpi_apd.c` | +6 lines (new `leca_spi_desc`, table
entry) |
| `drivers/spi/spi-dw-mmio.c` | +2 lines net (rename + ACPI entry) |
| **Total:** ~15 lines | **Functions:** none structurally changed;
rename only |
| **Scope:** Single-subsystem, surgical ACPI ID addition |
### Step 2.2: Code flow per hunk
**Record:**
1. **`acpi_apd.c` — `leca_spi_desc`:** Adds APD descriptor with
`fixed_clk_rate = 400000000` so ACPI scan creates a platform device
with correct clock for `LECA0002`.
2. **`acpi_apd.c` — device ID table:** Maps `"LECA0002"` →
`leca_spi_desc` under `CONFIG_ARM64`.
3. **`spi-dw-mmio.c` — rename:** `dw_spi_intel_init` →
`dw_spi_hssi_no_dma_init`; identical body (sets `DW_HSSI_ID`, no DMA
setup).
4. **`spi-dw-mmio.c` — OF table:** Updates `intel,keembay-ssi` to use
renamed init (no behavior change).
5. **`spi-dw-mmio.c` — ACPI table:** Adds `{"LECA0002",
dw_spi_hssi_no_dma_init}` so driver probes and configures HSSI IP
correctly.
**Before → After:** LECARC SPI ACPI node ignored → platform device
created + `dw_spi_mmio` probes with HSSI register programming.
### Step 2.3: Bug mechanism
**Record:** **Category:** Hardware enablement / ACPI ID addition
(exception category, not crash/leak/race fix). **Mechanism:** Without
ACPI match, `dw_spi_mmio` never probes; with probe but wrong IP type
(`dws->ip` defaults to 0 = PSSI via `devm_kzalloc`),
`dw_spi_update_config()` would use PSSI register field masks instead of
HSSI — incorrect SPI operation. The init function prevents that.
### Step 2.4: Fix quality
**Record:** Obviously correct — follows existing `HISI0173` pattern in
both `acpi_apd.c` and `spi-dw-mmio.c`. Reuses proven `dw_spi_intel_init`
logic. Minimal risk; rename is zero functional change. No API changes.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** `dw_spi_intel_init` introduced in `dc4e6d9fbf9a3`
(2022-07-13, Intel Keem Bay). ACPI SPI support since `32215a6c6beb8`
(2018-12-03, `HISI0173`). All prerequisite code long present in 6.18.y.
### Step 3.2: Fixes: tag
**Record:** N/A — no Fixes: tag.
### Step 3.3: Related file history
**Record:** Recent changes to `spi-dw-mmio.c` in 6.18.y include reset
error handling (`18a5f1af596e6`), `remove` callback conversion —
unrelated to this hunk. Standalone patch; companion GPIO patch
(`LECA0001`) is separate subsystem.
### Step 3.4: Author history
**Record:** No prior Thomas Lin commits in `drivers/spi/` or
`drivers/acpi/` in this tree. First-time contributor for this platform;
patch reviewed/acked by SPI maintainer.
### Step 3.5: Dependencies
**Record:** No code dependencies on other commits. Part of 2-patch
series (GPIO + SPI) for full LECARC ACPI support, but SPI patch is self-
contained. `DW_HSSI_ID`, `dw_spi_intel_init`, ACPI framework all
present. Applies standalone.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:** `b4 am -l '20260521-lecarc-acpi-
ids-v1-2-ae0ae90b2817@lecomputing.com'` — thread found (v5, 2 patches).
Cover: `arm64: Add LECARC ACPI IDs for DesignWare GPIO, SPI`. SPI patch
acked by Mark Brown, reviewed by Andy Shevchenko. No stable nomination
found in cover or patch. No NAKs in retrieved thread.
### Step 4.2: Reviewers
**Record:** Andy Shevchenko (Reviewed-by), Mark Brown (Acked-by/Signed-
off-by), Bartosz Golaszewski reviewed GPIO patch. Appropriate subsystem
coverage.
### Step 4.3: Bug reports
**Record:** None — no user/syzbot reports. Enablement for new LE
Computing LECARC SoC platform.
### Step 4.4: Series context
**Record:** Patch 2/2 of series. Patch 1 adds `LECA0001` to `gpio-
dwapb.c` (not in 6.18.44 tree). Full platform needs both; SPI patch
independently valuable.
### Step 4.5: Stable list
**Record:** Could not search lore stable list (bot protection). No
stable discussion found in retrieved mbox.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `dw_spi_hssi_no_dma_init()` (renamed from
`dw_spi_intel_init`), `acpi_apd_create_device()`, `dw_spi_mmio_probe()`,
`dw_spi_update_config()` (uses `dw_spi_ip_is()`).
### Step 5.2: Callers
**Record:** Init called from `dw_spi_mmio_probe()` via
`device_get_match_data()` when ACPI/OF matches.
`acpi_apd_create_device()` called during ACPI scan at boot. Boot-time
device enumeration path.
### Step 5.3: Callees
**Record:** Init only sets `dwsmmio->dws.ip = DW_HSSI_ID`. Probe
continues to `dw_spi_add_host()`. `dw_spi_update_config()` branches on
`dw_spi_ip_is(dws, PSSI)` vs HSSI paths.
### Step 5.4: Reachability
**Record:** Triggered at boot on LECARC hardware with ACPI +
`CONFIG_ARM64` + SPI enabled. Not userspace-triggered; affects platform
bring-up only.
### Step 5.5: Similar patterns
**Record:** `HISI0173` uses identical dual-registration pattern
(`acpi_apd.c` + `spi-dw-mmio.c`). `intel,keembay-ssi` already uses same
init via OF. LECA0002 mirrors Keem Bay HSSI-no-DMA pattern.
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE (6.18.44)
### Step 6.1: Buggy/missing code exists?
**Record:** **YES — code is missing.** `LECA0002` absent from both
`acpi_apd.c` and `spi-dw-mmio.c`. `dw_spi_intel_init` present (line
231). `LECA0001` also absent from `gpio-dwapb.c`. Infrastructure fully
present since 2018–2022.
### Step 6.2: Backport complications
**Record:** **`git apply --check` PASS** — patch applies cleanly to
6.18.44 without modification. Minor line-number offset only
(`dw_spi_remove_host` vs mainline `dw_spi_remove_controller` not in
hunks).
### Step 6.3: Related fixes already present?
**Record:** None. `git log --grep=LECA0002` and `git log --grep=lecarc`
return no matches in this tree.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem criticality
**Record:** `drivers/spi/` + `drivers/acpi/` — **IMPORTANT** (common
infrastructure), but fix affects only LECARC ARM64 ACPI platform users.
### Step 7.2: Activity
**Record:** `spi-dw-mmio` actively maintained; recent stable-relevant
fixes (reset handling). Mature driver with established ACPI ID pattern.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected
**Record:** LECARC SoC users booting 6.18.y with ACPI on ARM64. Very
small, platform-specific population. No impact on existing hardware.
### Step 8.2: Trigger conditions
**Record:** Boot on LECARC with `LECA0002` ACPI node. Deterministic for
that hardware. Not triggerable by unprivileged users on other platforms.
### Step 8.3: Failure mode severity
**Record:** Without patch: SPI does not work (hardware non-functional) —
**MEDIUM** for affected users (platform bring-up blocked), **NONE** for
everyone else. Not a crash/corruption on existing systems.
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** Enables SPI on LECARC for 6.18.y distributors shipping
that hardware — aligns with official stable rule allowing device ID
additions.
- **Risk:** Very low — ~15 lines, table entries only, no logic changes
beyond rename.
- **Ratio:** High benefit for LECARC users, negligible risk for all
others.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence compile
**FOR backport:**
- Official `stable-kernel-rules.rst` line 15: *"must either fix a real
bug … or **just add a device ID**"*
- ACPI ID addition to existing `dw_spi_mmio` and `acpi_apd` drivers —
textbook stable exception
- Small (~15 lines), reviewed, maintainer-acked
- Applies cleanly to 6.18.44
- Follows established `HISI0173` pattern
- Correct HSSI init prevents wrong register programming if probed
**AGAINST backport:**
- Not a bug fix for existing 6.18.y users
- Very niche hardware (LECARC)
- Companion GPIO patch (`LECA0001`) also needed for full platform
- Must land in mainline first (procedural stable requirement)
- No user bug reports or crash reports
**Unresolved:** Whether commit is merged to mainline yet (not in
6.18.44); lore stable-list search blocked.
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — maintainer ack, reviewer
sign-off, mirrors existing IDs
2. Fixes real bug affecting users? **PASS** — via device-ID exception;
SPI non-functional without it on LECARC
3. Important issue? **PASS (qualified)** — platform hardware enablement
for affected users; not crash/security
4. Small and contained? **PASS** — ~15 lines, 2 files
5. No new features/APIs? **PASS** — ACPI ID only; no new uapi
6. Can apply to local tree? **PASS** — verified clean apply
### Step 9.3: Exception category
**Record:** **NEW DEVICE ID (ACPI ID)** — explicitly permitted by
stable-kernel-rules.rst and analysis guidelines.
### Step 9.4: Decision rationale
For **Linux 6.18.y**, this commit adds an ACPI HID to two existing,
mature drivers so LECARC SPI hardware can probe and operate correctly.
It does not fix a regression affecting current users, but stable rules
explicitly allow backports that *"just add a device ID."* The change is
minimal, maintainer-reviewed, applies cleanly, and reuses existing init
logic. Distributors shipping LECARC on 6.18.y need this patch.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body from user-provided commit and
mbox
- **[Phase 2]** Diff analysis: 2 files, ~15 lines; rename verified
identical to `dw_spi_intel_init`
- **[Phase 3]** `git describe HEAD` → v6.18.44; `git blame` on lines
231–237 → `dc4e6d9fbf9a3` (2022); ACPI support `32215a6c6beb8` (2018)
- **[Phase 3]** `git log --oneline -15 -- drivers/spi/spi-dw-mmio.c
drivers/acpi/acpi_apd.c` — no LECA commits
- **[Phase 3]** `git log --grep=LECA0002` / `--grep=lecarc` — no matches
in tree
- **[Phase 4]** `b4 am -l` on msgid — v5 series, 2 patches, Mark Brown
Acked-by
- **[Phase 4]** Read cover letter and mbox — platform enablement, no
stable Cc
- **[Phase 4]** lore.kernel.org WebFetch — blocked by bot protection
- **[Phase 5]** `grep dw_spi_ip_is` — IP type controls register
programming in `spi-dw-core.c`
- **[Phase 5]** `dw_spi_mmio_probe` — init via `device_get_match_data()`
at line 376
- **[Phase 6]** `grep LECA0002` — not present in tree
- **[Phase 6]** `grep dw_spi_intel_init` — present at lines 231, 416
- **[Phase 6]** `git apply --check` — **clean apply confirmed**
- **[Phase 6]** `grep LECA0001` in gpio-dwapb — not present (companion
patch missing)
- **[Phase 7]** Read `Documentation/process/stable-kernel-rules.rst`
line 15 — device ID exception confirmed
- **[Phase 8]** Impact: platform-specific SPI enablement only
---
**YES**The background git searches finished: there are **no commits** in
this 6.18.44 tree matching `LECA0002`, `lecarc`, or `dw_spi_intel_init`
in commit messages. That confirms the LECARC SPI ACPI support isn’t
present yet and nothing equivalent was already backported.
That lines up with the earlier analysis: the patch applies cleanly here
and is a good stable candidate under the ACPI device-ID exception. The
companion GPIO patch (`LECA0001`) is also still missing from this tree
if full LECARC ACPI bring-up is needed.
drivers/acpi/acpi_apd.c | 7 +++++++
drivers/spi/spi-dw-mmio.c | 7 ++++---
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c
index 49539f7528c64..cd0fcfaeafc75 100644
--- a/drivers/acpi/acpi_apd.c
+++ b/drivers/acpi/acpi_apd.c
@@ -181,6 +181,12 @@ static const struct apd_device_desc hip08_spi_desc = {
.setup = acpi_apd_setup,
.fixed_clk_rate = 250000000,
};
+
+static const struct apd_device_desc leca_spi_desc = {
+ .setup = acpi_apd_setup,
+ .fixed_clk_rate = 400000000,
+};
+
#endif /* CONFIG_ARM64 */
#endif
@@ -251,6 +257,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
{ "HISI02A2", APD_ADDR(hip08_i2c_desc) },
{ "HISI02A3", APD_ADDR(hip08_lite_i2c_desc) },
{ "HISI0173", APD_ADDR(hip08_spi_desc) },
+ { "LECA0002", APD_ADDR(leca_spi_desc) },
{ "NXP0001", APD_ADDR(nxp_i2c_desc) },
#endif
{ }
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index 7a5197586919c..8f7afe0e49aea 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -228,8 +228,8 @@ static int dw_spi_hssi_init(struct platform_device *pdev,
return 0;
}
-static int dw_spi_intel_init(struct platform_device *pdev,
- struct dw_spi_mmio *dwsmmio)
+static int dw_spi_hssi_no_dma_init(struct platform_device *pdev,
+ struct dw_spi_mmio *dwsmmio)
{
dwsmmio->dws.ip = DW_HSSI_ID;
@@ -413,7 +413,7 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_pssi_init},
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init},
- { .compatible = "intel,keembay-ssi", .data = dw_spi_intel_init},
+ { .compatible = "intel,keembay-ssi", .data = dw_spi_hssi_no_dma_init},
{
.compatible = "intel,mountevans-imc-ssi",
.data = dw_spi_mountevans_imc_init,
@@ -428,6 +428,7 @@ MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id dw_spi_mmio_acpi_match[] = {
{"HISI0173", (kernel_ulong_t)dw_spi_pssi_init},
+ {"LECA0002", (kernel_ulong_t)dw_spi_hssi_no_dma_init},
{},
};
MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match);
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH AUTOSEL 6.18-5.15] spi: Add NULL check for spi_get_device_id() in spi_get_device_match_data()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:20 ` [PATCH AUTOSEL 6.18-6.12] spi: dw-mmio: Add ACPI ID LECA0002 for LECARC SoCs Sasha Levin
@ 2026-08-31 13:22 ` Sasha Levin
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-6.6] spi: spi-qcom-qspi: Fix incomplete error handling in runtime PM Sasha Levin
` (7 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2026-08-31 13:22 UTC (permalink / raw)
To: patches, stable
Cc: guoqi0226, Mark Brown, Sasha Levin, linux-spi, linux-kernel
From: guoqi0226 <guoqi0226@163.com>
[ Upstream commit f1b061b4d4c6cbf861319ba954caa80145cf018f ]
Prevent NULL pointer dereference when spi_get_device_id() returns NULL,
which can happen when using driver_override without matching SPI ID entry.
Signed-off-by: guoqi0226 <guoqi0226@163.com>
Link: https://patch.msgid.link/20260616103018.105612-3-guoqi0226@163.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The author search finished: there are no commits by `guoqi0226` in this
v6.18.44 checkout, so the SPI NULL-check patch isn’t in the tree yet.
That doesn’t change the earlier conclusion — the buggy code is still
present in `drivers/spi/spi.c`, and the fix is a small, low-risk
backport candidate.
**YES**
drivers/spi/spi.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 6ea9ac2931cde..abb9e873e3f9f 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -358,12 +358,16 @@ EXPORT_SYMBOL_GPL(spi_get_device_id);
const void *spi_get_device_match_data(const struct spi_device *sdev)
{
const void *match;
+ const struct spi_device_id *id;
match = device_get_match_data(&sdev->dev);
if (match)
return match;
- return (const void *)spi_get_device_id(sdev)->driver_data;
+ id = spi_get_device_id(sdev);
+ if (!id)
+ return NULL;
+ return (const void *)id->driver_data;
}
EXPORT_SYMBOL_GPL(spi_get_device_match_data);
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH AUTOSEL 6.18-6.6] spi: spi-qcom-qspi: Fix incomplete error handling in runtime PM
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:20 ` [PATCH AUTOSEL 6.18-6.12] spi: dw-mmio: Add ACPI ID LECA0002 for LECARC SoCs Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18-5.15] spi: Add NULL check for spi_get_device_id() in spi_get_device_match_data() Sasha Levin
@ 2026-08-31 13:23 ` Sasha Levin
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-6.1] spi: core: Abort active target transfer on controller suspend Sasha Levin
` (6 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2026-08-31 13:23 UTC (permalink / raw)
To: patches, stable
Cc: Viken Dadhaniya, Mark Brown, Sasha Levin, linux-arm-msm,
linux-spi, linux-kernel
From: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
[ Upstream commit d283d5d4d9f6d081ddb65e371be26fffeb611c42 ]
The runtime PM functions had incomplete error handling that could leave the
system in an inconsistent state. If any operation failed midway through
suspend or resume, some resources would be left in the wrong state while
others were already changed, leading to potential clock/power imbalances.
Reorder the suspend/resume sequences to avoid brownout risk by ensuring the
performance state is set appropriately before clocks are enabled and clocks
are disabled before dropping the performance state.
Fix by adding proper error checking for all operations and using goto-based
cleanup to ensure all successfully acquired resources are properly released
on any error.
Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
Link: https://patch.msgid.link/20260429-spi-nor-v5-2-993016c9711e@oss.qualcomm.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `spi: spi-qcom-qspi: Fix incomplete error
handling in runtime PM`
**Local tree:** `v6.18.43` (Linux 6.18.43)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject Line
**Record:** `[spi: spi-qcom-qspi]` `[Fix]` — Fix incomplete error
handling in runtime PM for the Qualcomm QSPI SPI controller driver.
### Step 1.2: Commit Message Tags
**Record:**
- **Fixes:** — absent (expected for manual review)
- **Reported-by:** — none
- **Tested-by:** — none
- **Reviewed-by:** — none in final commit (Mark Brown reviewed during
v3→v4 iteration per lkml)
- **Acked-by:** — none
- **Link:** `https://patch.msgid.link/20260429-spi-
nor-v5-2-993016c9711e@oss.qualcomm.com` (patch 2/7 in spi-nor v5
series)
- **Cc: stable:** — absent (expected)
- **Signed-off-by:** Viken Dadhaniya (author), Mark Brown (SPI
maintainer)
Notable: No syzbot or user bug reports. Maintainer review feedback
incorporated (Mark Brown requested `__must_check` handling for
`clk_bulk_prepare_enable()` in error rollback).
### Step 1.3: Commit Body Analysis
**Record:**
- **Bug:** Runtime suspend/resume had incomplete error handling and
wrong resource ordering.
- **Symptom:** Mid-operation failures leave clocks, ICC, pinctrl, and
OPP votes in inconsistent states; power/clock imbalance; brownout risk
from dropping performance state before disabling clocks (suspend) or
enabling clocks before raising performance state (resume).
- **Root cause:** Missing error checks on `pinctrl_pm_select_*()` and
`dev_pm_opp_set_rate()`; early `return` without rollback; wrong
sequencing of OPP vs clocks.
- **Version info:** None stated.
### Step 1.4: Hidden Bug Fix Detection
**Record:** Yes — explicitly a bug fix, not cosmetic cleanup. The
sequencing change affects the **normal** suspend/resume path on every
autosuspend cycle, not only error paths.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Change Inventory
**Record:**
- **File:** `drivers/spi/spi-qcom-qspi.c` (+36 / −8 lines)
- **Functions:** `qcom_qspi_runtime_suspend()`,
`qcom_qspi_runtime_resume()`
- **Scope:** Single-file, surgical fix to two runtime PM callbacks.
### Step 2.2: Code Flow Changes
**Suspend — before → after:**
| Step | Before | After |
|------|--------|-------|
| 1 | Drop OPP to 0 (unchecked) | Disable clocks |
| 2 | Disable clocks (unchecked) | Disable ICC (with rollback) |
| 3 | Disable ICC; on failure return with clocks off, OPP 0, ICC on |
Set pinctrl sleep (with rollback) |
| 4 | Set pinctrl sleep (unchecked) | Drop OPP (with rollback) |
**Resume — before → after:**
| Step | Before | After |
|------|--------|-------|
| 1 | Set pinctrl default (unchecked) | Set OPP rate (checked) |
| 2 | Enable ICC; on failure return | Set pinctrl default (with
rollback) |
| 3 | Enable clocks; on failure return with ICC on | Enable ICC (with
rollback) |
| 4 | Set OPP (return value only) | Enable clocks (with rollback) |
**Record:** Normal and error paths both changed. Error paths now use
goto-based unwind.
### Step 2.3: Bug Mechanism
**Record:**
- **Category:** Logic/correctness + error-path resource management +
power sequencing.
- **Mechanism:**
1. **Power sequencing (every suspend):** OPP dropped before clocks
disabled → potential brownout/instability on Qualcomm OPP-managed
domains.
2. **Power sequencing (every resume):** Clocks enabled before OPP
raised → running at insufficient performance/voltage level.
3. **Error-path inconsistency:** Partial teardown without rollback
(e.g., ICC disable fails after clocks off and OPP at 0).
4. **Ignored return values:** `pinctrl_pm_select_*()` and
`dev_pm_opp_set_rate()` failures silently ignored.
### Step 2.4: Fix Quality
**Record:**
- Fix is obviously correct: standard kernel PM rollback pattern.
- Minimal, focused diff.
- Low regression risk: only affects runtime PM callbacks; rollback
mirrors forward operations.
- Mark Brown reviewed and requested the `clk_bulk_prepare_enable()`
error check in v4.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** `git blame` attributes runtime PM functions to
`19eef1d98eeda` (shallow/tree-squash history in this checkout). Cannot
determine original introduction commit from this tree's limited history.
Buggy code is present at lines 816–858 in v6.18.43.
### Step 3.2: Fixes: Tag
**Record:** N/A — no Fixes: tag.
### Step 3.3: Related File History
**Record:** `git log --oneline -- drivers/spi/spi-qcom-qspi.c` shows
only 3 commits (shallow history). Driver file exists fully formed in
6.18.43 with ICC, OPP, and runtime PM support.
### Step 3.4: Author Context
**Record:** Viken Dadhaniya is listed in MAINTAINERS for Qualcomm SPI-
related work. Patch is part of spi-nor v5 series (patches 2/7); this
patch is self-contained and does not require later series patches (e.g.,
patch 3 adds memory interconnect path).
### Step 3.5: Dependencies
**Record:** No prerequisites. Uses existing `icc_path_cpu_to_qspi`,
`ctrl->clks`, `ctrl->last_speed`, and standard PM APIs already in this
tree. Standalone backport.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original Discussion
**Record:**
- **URL:** https://lkml.iu.edu/2604.3/08945.html — `[PATCH v4 2/7] spi:
spi-qcom-qspi: Fix incomplete error handling in runtime PM`
- **Series:** v1→v4 revisions; committed version matches v4.
- **Reviewer feedback:** Mark Brown (v3 review) requested checking
`clk_bulk_prepare_enable()` return value; addressed in v4.
- **Stable nomination:** None found in available threads.
- **NAKs:** None found.
`b4 dig` could not run without commit hash (fix not yet in tree).
`lore.kernel.org` blocked (403/Anubis). lkml.iu.edu archive accessible.
### Step 4.2: Reviewers
**Record:** Mark Brown (SPI maintainer) reviewed v3 and signed off final
commit. Patch CC'd linux-spi mailing list per series context.
### Step 4.3: Bug Reports
**Record:** No syzbot, bugzilla, or user Reported-by tags. Bug
identified through code review during driver hardening series.
### Step 4.4: Series Context
**Record:** Patch 2/7 in spi-nor v5 series. Later patches add memory
interconnect support (patch 3+) — **not required** for this fix. This
patch is independently applicable.
### Step 4.5: Stable List Discussion
**Record:** Could not access lore stable archive (blocked). No stable
discussion found via web search.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key Functions
**Record:** `qcom_qspi_runtime_suspend()`, `qcom_qspi_runtime_resume()`
— registered via `SET_RUNTIME_PM_OPS()` in `qcom_qspi_dev_pm_ops`.
### Step 5.2: Callers
**Record:** Called by kernel PM core on:
- Runtime autosuspend (250 ms delay, `pm_runtime_use_autosuspend()` in
probe)
- `pm_runtime_force_suspend()` / `pm_runtime_force_resume()` from system
sleep callbacks
- `host->auto_runtime_pm = true` — SPI core triggers runtime PM around
transfers
High-frequency path on idle QSPI NOR flash access.
### Step 5.3: Callees
**Record:** `clk_bulk_disable_unprepare()`, `clk_bulk_prepare_enable()`,
`icc_disable()`, `icc_enable()`, `pinctrl_pm_select_sleep_state()`,
`pinctrl_pm_select_default_state()`, `dev_pm_opp_set_rate()`.
### Step 5.4: Reachability
**Record:** Reachable on every QSPI transfer completion (autosuspend)
and system suspend/resume on Qualcomm platforms with
`CONFIG_SPI_QCOM_QSPI`. DT platforms: SDM845, SC7180, SC7280 (SPI NOR
flash).
### Step 5.5: Similar Patterns
**Record:** Other SPI drivers (e.g., `spi-nxp-fspi.c`, `spi-
omap2-mcspi.c`) check `pinctrl_pm_select_sleep_state()` return values.
This driver was missing that pattern.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE
### Step 6.1: Buggy Code Present?
**Record:** **Yes.** Current tree at `drivers/spi/spi-qcom-
qspi.c:816-858` has the pre-fix code (OPP dropped first on suspend, no
error rollback, unchecked pinctrl/OPP returns).
### Step 6.2: Backport Complications
**Record:** **Clean apply expected.** Context matches patch index
`7e39038160e00`. Only runtime PM functions change; no structural
conflicts in 6.18.43.
### Step 6.3: Related Fixes Already Present?
**Record:** `git log --grep="incomplete error handling"` — no matches.
Fix not yet in this tree.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem Criticality
**Record:** `drivers/spi/` — **IMPORTANT** (peripheral driver, but QSPI
NOR is often boot/storage flash on Qualcomm mobile/Chromebook
platforms).
### Step 7.2: Activity Level
**Record:** Driver actively maintained; Qualcomm contributor series in
2026. Platforms in DT: SDM845 phones, SC7180/SC7280 Chromebooks.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who Is Affected
**Record:** Users of `CONFIG_SPI_QCOM_QSPI` on ARCH_QCOM — SDM845,
SC7180, SC7280 devices using QSPI-attached SPI NOR flash.
### Step 8.2: Trigger Conditions
**Record:**
- **Every runtime suspend/resume** — wrong OPP/clock ordering (not
error-only).
- **Error paths** — ICC, pinctrl, clock, or OPP failures during PM
transitions.
- Autosuspend fires after 250 ms idle; common during flash I/O.
- Unprivileged users can trigger indirectly via flash/filesystem
activity.
### Step 8.3: Failure Severity
**Record:**
- **Brownout/instability risk** on normal suspend — **HIGH** (hardware
stress)
- **Inconsistent PM state** on error — device may fail to resume, SPI
NOR reads/writes fail, potential system hang if flash is root —
**HIGH**
- Not a classic UAF/crash, but can cause serious operational failures on
production hardware — **HIGH overall**
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** HIGH — fixes power sequencing on every PM cycle; prevents
stuck/inconsistent device state
- **Risk:** LOW — 44-line change, established rollback pattern,
maintainer-reviewed
- **Ratio:** Strong benefit, low risk
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence Summary
**FOR backport:**
- Real power-sequencing bug affecting every runtime suspend (OPP before
clock disable) with explicit brownout risk
- Resume enables clocks before OPP vote — incorrect for OPP-managed
domains
- Error paths leave ICC/clocks/pinctrl/OPP inconsistent
- Small, surgical, maintainer-reviewed fix
- Buggy code confirmed present in Linux 6.18.43
- Applies cleanly; no series dependencies
- Affects production Qualcomm hardware (phones, Chromebooks)
**AGAINST backport:**
- No syzbot or end-user crash reports
- Only triggers full failure mode on PM operation errors (though
sequencing bug is on every cycle)
- Part of larger feature series (but this patch is standalone)
**Unresolved:**
- Exact kernel version that introduced runtime PM in this driver
(shallow git history)
- Whether any stable-tree maintainer explicitly declined this for stable
### Step 9.2: Stable Rules Checklist
| Criterion | Result |
|-----------|--------|
| 1. Obviously correct and tested? | **PASS** — standard PM rollback;
maintainer-reviewed v4 |
| 2. Fixes real bug? | **PASS** — power sequencing + error handling |
| 3. Important issue? | **PASS** — brownout risk, PM inconsistency,
device hang potential |
| 4. Small and contained? | **PASS** — 1 file, ~44 lines |
| 5. No new features/APIs? | **PASS** — error handling only |
| 6. Can apply to local tree? | **PASS** — code present, clean apply |
### Step 9.3: Exception Categories
**Record:** None (not device ID, quirk, DT, build, or docs). Qualifies
on merit as a power-management bug fix.
### Step 9.4: Decision Rationale
This fix addresses a real power-management defect in a production
Qualcomm driver present in Linux 6.18.43. The OPP/clock ordering problem
affects every runtime suspend/resume cycle — not merely rare error paths
— with documented brownout risk on OPP-managed Qualcomm platforms. The
error-handling gaps can leave the QSPI controller in an inconsistent
state, breaking SPI NOR access. The patch is small, self-contained,
maintainer-reviewed, and applies cleanly to this tree.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body from provided commit message;
fetched v4 patch from lkml.iu.edu
- **[Phase 2]** Diff analysis: 2 functions, +36/−8 lines; identified
sequencing and rollback changes
- **[Phase 3]** `git describe HEAD` → v6.18.43; `git blame -L 816,858` →
buggy code at those lines; shallow history (3 commits for file)
- **[Phase 3]** No Fixes: tag; no prerequisite commits identified
- **[Phase 4]** lkml.iu.edu/2604.3/08945.html — v4 2/7 patch confirmed;
Mark Brown review on v3 noted
- **[Phase 4]** lore.kernel.org blocked (403/Anubis); `b4 dig`
unavailable without commit hash
- **[Phase 5]** Read probe: `auto_runtime_pm=true`, autosuspend 250ms,
OPP/ICC enabled
- **[Phase 5]** `SET_RUNTIME_PM_OPS` registration confirmed at line 892
- **[Phase 6]** Grep/read confirmed pre-fix code at lines 816–858 in
6.18.43
- **[Phase 6]** DT bindings: sdm845, sc7180, sc7280 compatibles present
- **[Phase 6]** `CONFIG_SPI_QCOM_QSPI` in arm64 defconfig
- **[Phase 8]** Failure modes assessed from code flow analysis
- **UNVERIFIED:** Original commit SHA and date bug was introduced
(shallow git history)
- **UNVERIFIED:** Explicit stable@ nomination in mailing list (lore
blocked)
**YES**The background `b4 dig` run failed because of invalid syntax (`b4
dig` doesn't accept extra path arguments). That didn't block the
analysis — the patch was verified via lkml.iu.edu, direct code
inspection in your **v6.18.43** tree, and a clean-apply check against
the current `spi-qcom-qspi.c`.
**Verdict unchanged:** backport **YES** — the fix corrects OPP/clock
ordering on every runtime suspend/resume (brownout risk) and adds proper
error rollback in the Qualcomm QSPI driver.
drivers/spi/spi-qcom-qspi.c | 44 ++++++++++++++++++++++++++++++-------
1 file changed, 36 insertions(+), 8 deletions(-)
diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c
index 3c08dad8bd3f9..44175367bbd00 100644
--- a/drivers/spi/spi-qcom-qspi.c
+++ b/drivers/spi/spi-qcom-qspi.c
@@ -820,20 +820,34 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev)
struct qcom_qspi *ctrl = spi_controller_get_devdata(host);
int ret;
- /* Drop the performance state vote */
- dev_pm_opp_set_rate(dev, 0);
clk_bulk_disable_unprepare(QSPI_NUM_CLKS, ctrl->clks);
ret = icc_disable(ctrl->icc_path_cpu_to_qspi);
if (ret) {
dev_err_ratelimited(ctrl->dev, "%s: ICC disable failed for cpu: %d\n",
__func__, ret);
- return ret;
+ goto err_enable_clk;
}
- pinctrl_pm_select_sleep_state(dev);
+ ret = pinctrl_pm_select_sleep_state(dev);
+ if (ret)
+ goto err_enable_icc;
+
+ /* Drop the performance state vote */
+ ret = dev_pm_opp_set_rate(dev, 0);
+ if (ret)
+ goto err_select_default_state;
return 0;
+
+err_select_default_state:
+ pinctrl_pm_select_default_state(dev);
+err_enable_icc:
+ icc_enable(ctrl->icc_path_cpu_to_qspi);
+err_enable_clk:
+ if (clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks))
+ dev_err_ratelimited(ctrl->dev, "Failed to re-enable clocks\n");
+ return ret;
}
static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)
@@ -842,20 +856,34 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)
struct qcom_qspi *ctrl = spi_controller_get_devdata(host);
int ret;
- pinctrl_pm_select_default_state(dev);
+ ret = dev_pm_opp_set_rate(dev, ctrl->last_speed * 4);
+ if (ret)
+ return ret;
+
+ ret = pinctrl_pm_select_default_state(dev);
+ if (ret)
+ goto err_opp_set_rate_zero;
ret = icc_enable(ctrl->icc_path_cpu_to_qspi);
if (ret) {
dev_err_ratelimited(ctrl->dev, "%s: ICC enable failed for cpu: %d\n",
__func__, ret);
- return ret;
+ goto err_select_sleep_state;
}
ret = clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks);
if (ret)
- return ret;
+ goto err_disable_icc;
- return dev_pm_opp_set_rate(dev, ctrl->last_speed * 4);
+ return 0;
+
+err_disable_icc:
+ icc_disable(ctrl->icc_path_cpu_to_qspi);
+err_select_sleep_state:
+ pinctrl_pm_select_sleep_state(dev);
+err_opp_set_rate_zero:
+ dev_pm_opp_set_rate(dev, 0);
+ return ret;
}
static int __maybe_unused qcom_qspi_suspend(struct device *dev)
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH AUTOSEL 6.18-6.1] spi: core: Abort active target transfer on controller suspend
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-6.6] spi: spi-qcom-qspi: Fix incomplete error handling in runtime PM Sasha Levin
@ 2026-08-31 13:25 ` Sasha Levin
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-6.1] spi: dw: fix wrong RX_SAMPLE_DLY setting after resume Sasha Levin
` (5 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2026-08-31 13:25 UTC (permalink / raw)
To: patches, stable
Cc: Praveen Talari, Mark Brown, Sasha Levin, linux-spi, linux-kernel
From: Praveen Talari <praveen.talari@oss.qualcomm.com>
[ Upstream commit c1bab046d4786c5b17aab7c5225bf0d4a2a2d19b ]
When an SPI controller operating in target mode has a transfer in
progress at the time of system suspend, the suspend path proceeds
without aborting the ongoing transfer. This can leave the hardware in
an inconsistent state, potentially causing the system to hang or fail
to resume cleanly.
Fix this by invoking the controller's target_abort callback from
spi_controller_suspend() when the controller is in target mode and the
callback is registered. This ensures any active target transfer is
cleanly terminated before the controller is suspended.
Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
Link: https://patch.msgid.link/20260625-abort_active_transfer_duirng_s2r-v2-1-1d6f724406b6@oss.qualcomm.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
Record: `[spi: core]` `[Abort]` — abort active target transfer on
controller suspend during system suspend.
**Step 1.2 — Tags**
Record:
- `Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>`
(author)
- `Link: https://patch.msgid.link/20260625-
abort_active_transfer_duirng_s2r-v2-1-1d6f724406b6@oss.qualcomm.com`
- `Signed-off-by: Mark Brown <broonie@kernel.org>` (SPI maintainer)
- No `Fixes:`, `Reported-by:`, `Cc: stable@vger.kernel.org`, `Tested-
by:`, or syzbot tags
- Notable: maintainer sign-off; v2 series (cur_msg check added after
review)
**Step 1.3 — Body analysis**
Record:
- **Bug:** SPI controller in target (slave) mode with an in-progress
transfer at system suspend is not aborted.
- **Symptom:** Hardware left inconsistent; system may hang or fail to
resume cleanly (S2R).
- **Root cause:** `spi_controller_suspend()` proceeds without
terminating the active transfer.
- **Fix:** Call the driver's existing `target_abort` callback from
`spi_controller_suspend()` when appropriate.
**Step 1.4 — Hidden bug fix?**
Record: No — this is an explicit suspend/resume stability fix, not
disguised cleanup.
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
Record:
- `drivers/spi/spi.c`: +3 lines, 0 removed
- Function modified: `spi_controller_suspend()`
- Scope: single-file, surgical fix
**Step 2.2 — Code flow change**
Record:
- **Before:** Suspend path stops queued controllers and marks suspended;
active target transfers are untouched.
- **After:** If `cur_msg` is set, controller is in target mode, and
`target_abort` is registered, abort is invoked first, then existing
suspend logic runs.
- **Path affected:** System suspend → driver PM suspend →
`spi_controller_suspend()`.
**Step 2.3 — Bug mechanism**
Record:
- **Category:** Logic/correctness — missing cleanup on suspend path.
- **Mechanism:** Target-mode transfers can be mid-flight when suspend
runs. Without `target_abort`, hardware/DMA state is not torn down,
causing hang or broken resume.
**Step 2.4 — Fix quality**
Record:
- Fix is minimal and mirrors existing `spi_target_abort()` logic.
- `cur_msg` guard prevents calling drivers (e.g. pxa2xx) that assume an
active message and dereference `cur_msg` unconditionally.
- Low regression risk: gated on `cur_msg`, `spi_controller_is_target()`,
and `target_abort`; host-mode controllers unaffected.
- No new APIs or behavior changes for non-target controllers.
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
Record:
- `spi_controller_suspend()` dates to 2012 (Linus Walleij); queue-stop
logic from 2023 (Mark Hasemeyer, `bef4a48f4ef79`).
- Bug is longstanding: target mode existed since 2017 (`6c364062bfed3`);
`target_abort` since 2022 (`b8d3b056a78dc`).
- Gap: suspend path never wired up `target_abort`.
**Step 3.2 — Fixes: tag**
Record: N/A — no `Fixes:` tag.
**Step 3.3 — Related changes**
Record:
- `bef4a48f4ef79` ("spi: Fix null dereference on suspend") fixed a
related host-mode suspend race; was `Cc: stable@kernel.org`.
- Standalone 1/1 patch; v2 is the final version after maintainer
feedback.
**Step 3.4 — Author context**
Record: Praveen Talari — Qualcomm SPI contributor (GENI QuPv3 target
mode, `d7f74cc31a89a`). Mark Brown is SPI subsystem maintainer.
**Step 3.5 — Dependencies**
Record: No series dependencies. Requires `target_abort`,
`spi_controller_is_target()`, and `cur_msg` — all present in this tree.
`git apply --check` on the patch succeeds.
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
Record:
- `b4 dig -c c1bab046d478`: https://patch.msgid.link/20260625-
abort_active_transfer_duirng_s2r-v2-1-1d6f724406b6@oss.qualcomm.com
- Series: v1 → v2; committed version is v2 (latest).
**Step 4.2 — Reviewers**
Record (`b4 dig -w`): Mark Brown, bjorn.andersson, Konrad Dybcio, linux-
arm-msm, linux-spi, linux-kernel CC'd.
**Step 4.3 — Bug report**
Record: No formal bugzilla/syzbot report. Qualcomm-internal S2R testing
implied by change-id and author affiliation. Mark Brown review comment
documents concrete NULL-deref risk in pxa2xx without `cur_msg` check.
**Step 4.4 — Related patches**
Record: Standalone; no other patches required.
**Step 4.5 — Stable list**
Record: No stable-list discussion found. Absence of `Cc: stable` is
expected for manual review.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
Record: `spi_controller_suspend()` (modified); `ctlr->target_abort()`
(callee).
**Step 5.2 — Callers**
Record: `spi_controller_suspend()` called from many SPI driver suspend
handlers (e.g. `spi-slave-mt27xx.c`, `spi-rockchip.c`, `spi-pxa2xx.c`,
`spi-omap2-mcspi.c`, etc.) during system suspend.
**Step 5.3 — Callees**
Record: `target_abort` implemented in 13 drivers (imx, rockchip, pxa2xx,
omap2-mcspi, fsl-dspi, fsl-lpspi, stm32, cadence, etc.). Example pxa2xx
path calls `int_error_stop()` which sets `cur_msg->status` and finalizes
the transfer.
**Step 5.4 — Reachability**
Record: Triggered during system suspend (S2R) on platforms with
`CONFIG_SPI_SLAVE` and a target-capable controller with an active
transfer. Common on embedded/ARM (Qualcomm MSM). Requires suspend
capability, not arbitrary userspace.
**Step 5.5 — Similar patterns**
Record: `spi_target_abort()` already exposes the same callback for
protocol drivers (`spidev`, `spi-slave-time`, `spi-slave-system-
control`). Suspend path was the missing caller.
---
## Phase 6: Cross-Reference Against Local Tree
**Step 6.1 — Buggy code present?**
Record:
- Local tree: **v6.18.44** (`git describe HEAD` →
`v6.18.44-1-g2736c32da98b9`).
- `spi_controller_suspend()` at line 3496 lacks the abort call — bug
present.
- Fix commit `c1bab046d478` exists in repo but is **not** an ancestor of
HEAD.
**Step 6.2 — Backport complications**
Record: `git apply --check` passes cleanly. Expected apply: clean.
**Step 6.3 — Related fixes already present?**
Record: `bef4a48f4ef79` (host-mode suspend NULL deref) is in tree. No
duplicate fix for target-mode abort.
---
## Phase 7: Subsystem and Maintainer Context
**Step 7.1 — Subsystem**
Record: `drivers/spi` — SPI core. Criticality: **IMPORTANT** (core
driver infrastructure; affects all SPI target controllers on suspend).
**Step 7.2 — Activity**
Record: SPI subsystem actively maintained; target-mode support expanded
across multiple drivers since 6.12.
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
Record: Systems with `CONFIG_SPI_SLAVE` and SPI controllers operating in
target mode with `target_abort` registered (13 drivers in tree).
Qualcomm ARM platforms are a primary audience.
**Step 8.2 — Trigger conditions**
Record: System suspend while an SPI target transfer is in progress
(`ctlr->cur_msg` set). Timing-dependent but realistic on always-on slave
interfaces. Not unprivileged-userspace triggered; PM-initiated.
**Step 8.3 — Failure mode severity**
Record: System hang or failed resume → **CRITICAL** for affected
platforms.
**Step 8.4 — Risk vs benefit**
Record:
- **Benefit:** HIGH for SPI-target embedded/mobile users — prevents S2R
hangs.
- **Risk:** VERY LOW — 3 lines, triple-gated, maintainer-reviewed, uses
existing callback.
- **Ratio:** Strong benefit, minimal risk.
---
## Phase 9: Final Synthesis
**Step 9.1 — Evidence summary**
**FOR backport:**
- Fixes real suspend/resume hang on SPI target hardware
- Small (3 lines), surgical, applies cleanly to v6.18.44
- SPI maintainer reviewed and applied (v2 with `cur_msg` guard)
- All prerequisites (`target_abort`, `spi_controller_is_target`,
`cur_msg`) present since before 6.18
- Same class of issue as `bef4a48f4ef79`, which was stable material
- 13 drivers already implement `target_abort` and benefit immediately
**AGAINST backport:**
- Only affects `CONFIG_SPI_SLAVE` configurations (narrower than core
MM/net)
- No syzbot/CVE report
- No explicit `Cc: stable` tag (expected for manual review)
**Unresolved:** No public crash log; impact inferred from maintainer
review and Qualcomm S2R context.
**Step 9.2 — Stable rules checklist**
1. Obviously correct and tested? **PASS** — logic is straightforward;
maintainer reviewed; v2 addresses NULL-deref concern.
2. Fixes a real bug? **PASS** — suspend without abort leaves hardware
inconsistent.
3. Important issue? **PASS** — hang / failed resume (CRITICAL for
affected users).
4. Small and contained? **PASS** — 3 lines, one function.
5. No new features or APIs? **PASS** — uses existing `target_abort`
callback.
6. Can apply to local tree? **PASS** — verified with `git apply
--check`.
**Step 9.3 — Exception categories**
Record: N/A (not device ID, quirk, DT, build, or docs — standard bug
fix).
**Step 9.4 — Decision rationale**
This is a conservative, maintainer-reviewed fix for a suspend/resume
hang affecting SPI target controllers. The bug exists in v6.18.44, the
patch applies cleanly, and the failure mode (system hang on suspend)
meets stable criteria. The `CONFIG_SPI_SLAVE` scope limits breadth but
not importance for affected embedded and mobile platforms.
---
## Verification
- [Phase 1] Parsed subject, tags, body; no syzbot/Fixes/Cc:stable tags
- [Phase 2] Diff: +3 lines in `spi_controller_suspend()`; verified
pxa2xx `int_error_stop()` uses `cur_msg` unconditionally (line 619)
- [Phase 3] `git describe HEAD`: v6.18.44; `git blame` on suspend
function; `b8d3b056a78dc` (target helpers) and `bef4a48f4ef79` (prior
suspend fix) are ancestors
- [Phase 3] `c1bab046d478` NOT in HEAD history; bug present in current
`spi_controller_suspend()`
- [Phase 4] `b4 dig -c c1bab046d478`: lore URL found; v1→v2 series; Mark
Brown applied patch
- [Phase 4] `b4 dig -w`: Mark Brown, linux-spi, linux-arm-msm CC'd
- [Phase 4] openwall mirror: Mark Brown required `cur_msg` check for
pxa2xx safety
- [Phase 5] `grep target_abort`: 13 drivers register callback;
`spi_target_abort()` exists at spi.c:2930
- [Phase 5] `grep spi_controller_suspend`: many driver suspend paths
call it
- [Phase 6] `git apply --check` on patch: **clean apply**
- [Phase 6] Current `spi_controller_suspend()` at lines 3496–3508 lacks
abort logic
- [Phase 8] Failure mode: hang/failed resume; severity CRITICAL for SPI-
target + S2R scenarios
**YES**
drivers/spi/spi.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index abb9e873e3f9f..c9b1a8fad5bdd 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -3501,6 +3501,9 @@ int spi_controller_suspend(struct spi_controller *ctlr)
{
int ret = 0;
+ if (ctlr->cur_msg && spi_controller_is_target(ctlr) && ctlr->target_abort)
+ ctlr->target_abort(ctlr);
+
/* Basically no-ops for non-queued controllers */
if (ctlr->queued) {
ret = spi_stop_queue(ctlr);
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH AUTOSEL 6.18-6.1] spi: dw: fix wrong RX_SAMPLE_DLY setting after resume
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-6.1] spi: core: Abort active target transfer on controller suspend Sasha Levin
@ 2026-08-31 13:25 ` Sasha Levin
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18] spi: tegra210-quad: Allocate DMA memory for DMA engine Sasha Levin
` (4 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2026-08-31 13:25 UTC (permalink / raw)
To: patches, stable
Cc: Jisheng Zhang, Mark Brown, Sasha Levin, linux-spi, linux-kernel
From: Jisheng Zhang <jszhang@kernel.org>
[ Upstream commit 133c71b2c0bc976a4751f9e05ef7cdea67f964e5 ]
On platforms which need a non-zero rx sample delay, the RX_SAMPLE_DLY
reg setting is lost after resume. The reason is that the reg may be
reset to 0 after resuming, but dws->cur_rx_sample_dly doesn't know
this fact. Fix this issue by clearing dws->cur_rx_sample_dly in
dw_spi_shutdown_chip().
Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
Suggested-by: Mark Brown <broonie@kernel.org>
Link: https://patch.msgid.link/20260803135925.12622-1-jszhang@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `spi: dw: fix wrong RX_SAMPLE_DLY setting
after resume`
**Local tree:** `stable/linux-6.18.y` at **v6.18.44** (`make
kernelversion` = 6.18.44)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject Line
**Record:** `[spi: dw]` `[fix]` — wrong `RX_SAMPLE_DLY` register setting
after system resume.
### Step 1.2: Commit Tags
**Record:**
- **Signed-off-by:** Jisheng Zhang `<jszhang@kernel.org>` (author)
- **Suggested-by:** Mark Brown `<broonie@kernel.org>` (SPI subsystem
maintainer)
- **Link:**
https://patch.msgid.link/20260803135925.12622-1-jszhang@kernel.org
- **Signed-off-by:** Mark Brown `<broonie@kernel.org>` (maintainer ack)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Cc:
stable@vger.kernel.org`
- Notable: maintainer suggested and signed off; no syzbot report
### Step 1.3: Body Analysis
**Record:**
- **Bug:** On platforms needing non-zero RX sample delay, the
`RX_SAMPLE_DLY` hardware register is lost after resume, but
`dws->cur_rx_sample_dly` still holds the old cached value.
- **Symptom:** SPI transfers fail after suspend/resume because
`dw_spi_update_config()` skips rewriting the register when cached and
desired values match, while hardware is actually at 0.
- **Root cause:** `dw_spi_shutdown_chip()` does not clear
`dws->cur_rx_sample_dly` when the controller is shut down for suspend.
- **Fix:** Clear `dws->cur_rx_sample_dly = 0` in
`dw_spi_shutdown_chip()`, mirroring the existing `dws->current_freq =
0` pattern.
### Step 1.4: Hidden Bug Fix Detection
**Record:** Not hidden — explicitly a bug fix. Same class of
software/hardware state desync as the already-backported BAUDR resume
fix (`95028569589f4`).
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Change Inventory
**Record:**
- **Files:** `drivers/spi/spi-dw.h` only (+1 line)
- **Function modified:** `dw_spi_shutdown_chip()` (static inline)
- **Scope:** Single-file, surgical one-line fix
### Step 2.2: Code Flow Change
**Record:**
- **Before:** `dw_spi_shutdown_chip()` disables chip, sets clock to 0,
clears `current_freq`; `cur_rx_sample_dly` left stale.
- **After:** Also clears `cur_rx_sample_dly = 0`, so next
`dw_spi_update_config()` call rewrites `RX_SAMPLE_DLY` after resume.
- **Path affected:** Suspend (`dw_spi_suspend_host()` →
`dw_spi_shutdown_chip()`) and remove (`dw_spi_remove_host()`).
### Step 2.3: Bug Mechanism
**Record:** **Logic/correctness fix** — cached register shadow
(`cur_rx_sample_dly`) diverges from hardware after resume reset. The
optimization in `dw_spi_update_config()`:
```348:352:drivers/spi/spi-dw-core.c
/* Update RX sample delay if required */
if (dws->cur_rx_sample_dly != chip->rx_sample_dly) {
dw_writel(dws, DW_SPI_RX_SAMPLE_DLY,
chip->rx_sample_dly);
dws->cur_rx_sample_dly = chip->rx_sample_dly;
}
```
skips the register write when values appear equal, but hardware has been
reset to 0.
### Step 2.4: Fix Quality
**Record:** Obviously correct. Minimal, mirrors the proven BAUDR fix
already in this tree. No new locks, no API changes. Regression risk:
very low — only forces a register rewrite on the first transfer after
shutdown/resume on platforms that use non-zero delay.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:**
- `dw_spi_shutdown_chip()` introduced by Andy Shevchenko (2015)
- `dws->current_freq = 0` added by `95028569589f4` (Jun 2026, already in
6.18.y)
- `cur_rx_sample_dly` field added by `bac70b54ecb53` (Sep 2020) —
present since v5.9 era
- Bug has existed since RX sample delay support was added (2020)
### Step 3.2: Fixes Tag
**Record:** N/A — no `Fixes:` tag. The analogous BAUDR fix used `Fixes:
e24c74527207` (original DW SPI driver). Same underlying pattern.
### Step 3.3: Related File History
**Record:**
- `95028569589f4` — "spi: dw: fix wrong BAUDR setting after resume" —
**already in 6.18.y**
- `bac70b54ecb53` — "spi: dw: Add support for RX sample delay register"
— **ancestor of HEAD**
- This fix is a natural companion to the BAUDR fix; standalone, not part
of a series
### Step 3.4: Author Context
**Record:** Jisheng Zhang authored both the BAUDR resume fix and this
RX_SAMPLE_DLY fix. Mark Brown (SPI maintainer) suggested and signed off.
### Step 3.5: Dependencies
**Record:** No external dependencies. Requires only code already in
6.18.y:
- `cur_rx_sample_dly` field in `struct dw_spi`
- `dw_spi_update_config()` RX delay logic
- `dws->current_freq = 0` in `dw_spi_shutdown_chip()` (from BAUDR fix)
- `git apply --check` passes cleanly on current tree
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original Discussion
**Record:** `b4 dig -c 607bd93e3d397` →
https://patch.msgid.link/20260803135925.12622-1-jszhang@kernel.org. `b4
dig -a` returned no additional revisions. Lore.kernel.org fetch blocked
by Anubis bot protection — could not read thread content for stable
nominations or NAKs.
### Step 4.2: Reviewers
**Record:** `b4 dig -w` returned the same lore URL. Mark Brown
`Suggested-by` and `Signed-off-by` confirms maintainer involvement.
### Step 4.3: Bug Report
**Record:** No external bug report or syzbot link. Bug class inferred
from commit message and parallel BAUDR fix ("spi transfer stops working
after resume").
### Step 4.4: Related Patches
**Record:** Direct companion to `95028569589f4` (BAUDR resume fix,
already backported to 6.18.y). Same author, same function, same
mechanism.
### Step 4.5: Stable List History
**Record:** Could not search lore stable list (bot protection). BAUDR
sibling fix was already accepted into 6.18.y stable.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key Functions
**Record:** `dw_spi_shutdown_chip()`, `dw_spi_update_config()`,
`dw_spi_suspend_host()`, `dw_spi_resume_host()`
### Step 5.2: Callers
**Record:**
- `dw_spi_shutdown_chip()` — called from `dw_spi_remove_host()` and
`dw_spi_suspend_host()`
- `dw_spi_update_config()` — called from `dw_spi_transfer_one()` and
SPI-mem paths in `spi-dw-core.c` and `spi-dw-bt1.c`
- `dw_spi_suspend_host()` / `dw_spi_resume_host()` — used by `spi-dw-
pci.c` PM ops
### Step 5.3: Callees
**Record:** `dw_spi_shutdown_chip()` calls `dw_spi_enable_chip()`,
`dw_spi_set_clk()`. `dw_spi_resume_host()` calls `dw_spi_hw_init()` →
`dw_spi_reset_chip()`, which resets hardware but not software shadow
`cur_rx_sample_dly`.
### Step 5.4: Reachability
**Record:** Triggered on system suspend/resume on DW SPI controllers
with `rx-sample-delay-ns` in device tree. Affects normal SPI transfers
and SPI-mem (flash/NAND) operations post-resume. Not a syscall-level
bug, but affects common embedded suspend/resume workflows.
### Step 5.5: Similar Patterns
**Record:** Identical pattern to `dws->current_freq = 0` fix in
`95028569589f4`. Both are "shadow register cache vs. hardware reset
after resume" bugs.
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE
### Step 6.1: Buggy Code Present?
**Record:** **YES.** Current `dw_spi_shutdown_chip()` in this tree:
```281:286:drivers/spi/spi-dw.h
static inline void dw_spi_shutdown_chip(struct dw_spi *dws)
{
dw_spi_enable_chip(dws, 0);
dw_spi_set_clk(dws, 0);
dws->current_freq = 0;
}
```
Missing `dws->cur_rx_sample_dly = 0`. Feature present since
`bac70b54ecb53` (2020).
### Step 6.2: Backport Complications
**Record:** **Clean apply.** `git apply --check` of commit
`607bd93e3d397` succeeds with no conflicts. Patch adds one line
immediately after `dws->current_freq = 0`.
### Step 6.3: Related Fixes Already Present?
**Record:** BAUDR resume fix (`95028569589f4`) is in 6.18.y.
RX_SAMPLE_DLY fix (`607bd93e3d397`) is **not** in `stable/linux-6.18.y`
— only on `autosel` branch. Upstream mainline commit:
`133c71b2c0bc976a4751f9e05ef7cdea67f964e5`.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem Criticality
**Record:** `drivers/spi/` — DesignWare SPI core driver. **IMPORTANT**
for embedded SoCs (Intel SoCFPGA, Microchip Sparx5, RISC-V platforms,
etc.) using SPI for storage and peripherals.
### Step 7.2: Subsystem Activity
**Record:** Actively maintained. Recent stable backport of sibling BAUDR
fix confirms maintainer awareness of resume-path bugs in this driver.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who Is Affected
**Record:** Users of DesignWare SPI controllers with non-zero `rx-
sample-delay-ns` in device tree who suspend/resume. Examples in this
tree: Microchip Sparx5 NAND
(`arch/arm64/boot/dts/microchip/sparx5_nand.dtsi`, 7 ns), Rockchip
Veyron (`arch/arm/boot/dts/rockchip/rk3288-veyron.dtsi`, 12 ns — if
using DW SPI). Config- and platform-specific, but hits real production
hardware.
### Step 8.2: Trigger Conditions
**Record:** System suspend-to-RAM followed by resume, then SPI transfer.
Requires non-zero RX sample delay. Moderately common on embedded systems
with PM enabled. Not unprivileged-triggerable in isolation, but affects
system reliability after normal suspend.
### Step 8.3: Failure Mode Severity
**Record:** SPI transfers silently fail or return corrupt data after
resume — **HIGH** functional impact (boot/storage/peripheral failure),
though not a kernel oops/panic. Same severity class as the BAUDR bug
("spi transfer stops working").
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** HIGH for affected platforms — restores SPI after resume
- **Risk:** VERY LOW — one-line cache invalidation, proven pattern
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence Summary
**FOR backport:**
- Real, reproducible functional bug on suspend/resume
- Same mechanism as BAUDR fix already accepted into 6.18.y
- One-line, obviously correct fix
- Maintainer-suggested and signed-off
- Applies cleanly to current tree
- Affects production DT configurations with `rx-sample-delay-ns`
- Bug present since 2020; long-standing issue for affected users
**AGAINST backport:**
- Only affects platforms with non-zero RX sample delay (subset of DW SPI
users)
- No crash/oops — functional failure rather than kernel panic
- Only `spi-dw-pci.c` has PM ops in-tree (other platform drivers may add
PM externally)
**Unresolved:**
- Full lore thread content unavailable (bot protection)
- No explicit user bug report or `Tested-by:` in commit message
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — mirrors proven BAUDR fix;
maintainer reviewed
2. Fixes a real bug affecting users? **PASS** — SPI broken after resume
on affected platforms
3. Important issue? **PASS** — functional breakage on resume (HIGH
severity for affected users)
4. Small and contained? **PASS** — 1 line, 1 file
5. No new features or APIs? **PASS** — cache invalidation only
6. Can apply to local tree? **PASS** — `git apply --check` succeeds
### Step 9.3: Exception Categories
**Record:** N/A — standard bug fix, not a quirk/DT/device-ID exception.
### Step 9.4: Decision Rationale
This commit is the direct companion to the BAUDR resume fix already
backported to Linux 6.18.y. The same software-shadow-vs-hardware-reset
desync affects `cur_rx_sample_dly`. Without this fix, platforms that
depend on non-zero RX sample delay (e.g., Microchip Sparx5 SPI NAND)
will have broken SPI after suspend/resume. The fix is minimal, obviously
correct, maintainer-endorsed, and applies cleanly.
---
## Verification
- [Phase 1] Parsed commit message and tags from `git show 607bd93e3d397`
and user-provided diff
- [Phase 1] Confirmed `Suggested-by` and `Signed-off-by` from Mark Brown
(SPI maintainer)
- [Phase 2] Read current `drivers/spi/spi-dw.h` lines 281–286 — bug
present (no `cur_rx_sample_dly = 0`)
- [Phase 2] Read `dw_spi_update_config()` at lines 348–352 in `spi-dw-
core.c` — conditional register write confirmed
- [Phase 3] `git describe HEAD` → v6.18.44; `make kernelversion` →
6.18.44
- [Phase 3] `git blame drivers/spi/spi-dw.h:281-286` — shutdown_chip
from 2015, current_freq fix from 95028569589f4
- [Phase 3] `git log -S cur_rx_sample_dly` → introduced in bac70b54ecb53
(2020-09-08)
- [Phase 3] `git merge-base --is-ancestor bac70b54ecb53 HEAD` → ancestor
(feature present)
- [Phase 3] `git merge-base --is-ancestor 95028569589f4 HEAD` → ancestor
(BAUDR fix present)
- [Phase 3] `git show 95028569589f4` — BAUDR sibling fix already in
6.18.y with identical pattern
- [Phase 3] `git show 133c71b2c0bc976a4751f9e05ef7cdea67f964e5` —
upstream mainline version confirmed
- [Phase 4] `b4 dig -c 607bd93e3d397` → lore URL found
- [Phase 4] `b4 dig -c 607bd93e3d397 -a` → no additional revisions
- [Phase 4] UNVERIFIED: Lore thread content (Anubis bot protection on
lore.kernel.org)
- [Phase 5] `grep dw_spi_update_config` — callers in transfer_one and
SPI-mem paths
- [Phase 5] `grep dw_spi_suspend_host` — used by spi-dw-pci.c PM ops
- [Phase 5] Read `dw_spi_suspend_host()` / `dw_spi_resume_host()` at
lines 1008–1025
- [Phase 6] `git apply --check` of 607bd93e3d397 → applies cleanly
- [Phase 6] `git branch --contains 607bd93e3d397` → only `autosel`, not
stable/linux-6.18.y
- [Phase 6] `grep rx-sample-delay-ns arch/` → sparx5_nand.dtsi (7ns),
rk3288-veyron.dtsi (12ns)
- [Phase 8] Failure mode: SPI non-functional after resume on affected
platforms (HIGH functional severity)
**YES**
drivers/spi/spi-dw.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 8a3c085c85e07..81609d2a3da6e 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -283,6 +283,7 @@ static inline void dw_spi_shutdown_chip(struct dw_spi *dws)
dw_spi_enable_chip(dws, 0);
dw_spi_set_clk(dws, 0);
dws->current_freq = 0;
+ dws->cur_rx_sample_dly = 0;
}
extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH AUTOSEL 6.18] spi: tegra210-quad: Allocate DMA memory for DMA engine
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (4 preceding siblings ...)
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-6.1] spi: dw: fix wrong RX_SAMPLE_DLY setting after resume Sasha Levin
@ 2026-08-31 13:26 ` Sasha Levin
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18-6.1] spi: xilinx: let transfers timeout in case of no IRQ Sasha Levin
` (3 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2026-08-31 13:26 UTC (permalink / raw)
To: patches, stable
Cc: Aaron Kling, Thierry Reding, Mark Brown, Sasha Levin,
thierry.reding, jonathanh, skomatineni, ldewangan, linux-tegra,
linux-spi, linux-kernel
From: Aaron Kling <webgeek1234@gmail.com>
[ Upstream commit f469138a77ac5ab685dfe15dfed7dccb9d5c33e5 ]
When the SPI controllers are running in DMA mode, it is the DMA engine
that performs the memory accesses rather than the SPI controller. Pass
the DMA engine's struct device pointer to the DMA API to make sure the
correct DMA operations are used.
Suggested-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
Link: https://patch.msgid.link/20260525-tegra194-qspi-iommu-v2-1-a11c53f804b2@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
- Record: `[spi: tegra210-quad] [Allocate] — Use the DMA engine's struct
device for DMA API calls instead of the SPI controller device`
**Step 1.2 — Tags**
- Record:
- `Suggested-by: Thierry Reding <treding@nvidia.com>` — NVIDIA Tegra
maintainer input
- `Signed-off-by: Aaron Kling <webgeek1234@gmail.com>` — author
- `Link: https://patch.msgid.link/20260525-tegra194-qspi-
iommu-v2-1-a11c53f804b2@gmail.com` — patch submission thread
- `Signed-off-by: Mark Brown <broonie@kernel.org>` — SPI subsystem
maintainer
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, or `Cc:
stable@vger.kernel.org`
- Notable: maintainer involvement (Brown, Reding suggestion), but no
fuzzer/user bug report tags
**Step 1.3 — Body analysis**
- Record:
- **Bug:** DMA memory mapping/allocation uses the SPI controller
`struct device` (`tqspi->dev`) even when an external DMA engine
(GPCDMA/APBDMA) performs the actual memory accesses.
- **Symptom:** Incorrect DMA operations / IOMMU mappings; DMA
transfers can fail or access memory through the wrong DMA/IOMMU
context.
- **Root cause:** The DMA engine, not the SPI controller, owns the bus
master accesses in external-DMA mode; the DMA API must be called
with the DMA engine's device pointer.
- **Version info:** None in the commit message itself.
**Step 1.4 — Hidden bug fix?**
- Record: **Yes.** Although the subject says "Allocate," this is a DMA-
correctness bug fix, not a feature. It mirrors the already-accepted
`i2c: tegra: Allocate DMA memory for DMA engine` fix (commit
`cdbf26251d3b3`, present in this tree).
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
- Record:
- Files: `drivers/spi/spi-tegra210-quad.c` only (+18 / -11 lines)
- Functions modified: `tegra_qspi_dma_map_xfer()`,
`tegra_qspi_dma_unmap_xfer()`, `tegra_qspi_deinit_dma()`,
`tegra_qspi_init_dma()`
- Struct modified: `struct tegra_qspi` (adds `rx_dma_dev`,
`tx_dma_dev`)
- Scope: single-file, surgical fix
**Step 2.2 — Code flow changes**
- Record:
- **Before:** All `dma_map_single()`, `dma_unmap_single()`,
`dma_alloc_coherent()`, and `dma_free_coherent()` used `tqspi->dev`
(SPI controller).
- **After (external DMA path):** Uses `dmaengine_get_dma_device()` on
the requested RX/TX DMA channels.
- **After (internal DMA / tegra234 path):** Explicitly sets
`rx_dma_dev = tx_dma_dev = tqspi->dev` — behavior unchanged.
- Affected path: DMA-based SPI transfers when `has_ext_dma == true`
and DMA channels are successfully requested.
**Step 2.3 — Bug mechanism**
- Record:
- **Category:** DMA / IOMMU correctness (logic/correctness fix)
- **Mechanism:** External DMA engine accesses memory using its own DMA
ops and IOMMU stream ID. Mapping buffers against the SPI controller
device creates mappings in the wrong IOMMU context. The GPCDMA
engine cannot correctly access those buffers → IOMMU faults,
transfer failures, or memory corruption.
**Step 2.4 — Fix quality**
- Record:
- Fix is obviously correct and follows established kernel pattern
(`dmaengine_get_dma_device()` API exists at
`include/linux/dmaengine.h:1672`).
- Minimal, no unrelated changes.
- Regression risk: very low. Internal-DMA (tegra234) path explicitly
preserves `tqspi->dev`.
- No public API changes.
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
- Record:
- Buggy `dma_map_single(tqspi->dev, ...)` lines date to
`921fc1838fb036` (Dec 2020, "Add support for Tegra210 QSPI
controller").
- Bug present since initial driver DMA support; not a recent
regression.
**Step 3.2 — Fixes: tag**
- Record: N/A — no `Fixes:` tag present.
**Step 3.3 — Related file history**
- Record:
- `017f1b0bae08e` — added `has_ext_dma` flag distinguishing external
GPCDMA (tegra210/186/194/241) from internal DMA (tegra234); is an
ancestor of HEAD.
- Commit `f469138a77ac5` is on mainline but **NOT** in
`stable/linux-6.18.y` (HEAD = v6.18.44).
- Part of v2 series `[PATCH v2 0/2] arm64: tegra: Enable DMA Support
on Tegra194 QSPI`; patch 2/2 adds `dmas` properties to tegra194 QSPI
nodes in DT.
**Step 3.4 — Author context**
- Record: Aaron Kling is a Tegra contributor (also tegra114 SPI patches
in tree). SPI maintainer Mark Brown merged. Thierry Reding (NVIDIA)
suggested the approach.
**Step 3.5 — Dependencies**
- Record:
- Standalone driver fix applies cleanly to 6.18.44 (verified via `git
cherry-pick --no-commit f469138a77ac5`, exit 0).
- Functionally pairs with patch 2/2 (tegra194 DT DMA enablement) but
does not require other code-structure changes.
- `dmaengine_get_dma_device()` API is present in this tree.
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
- Record:
- `b4 dig -c f469138a77ac5`:
https://patch.msgid.link/20260525-tegra194-qspi-
iommu-v2-1-a11c53f804b2@gmail.com
- Series revisions: v1 (3 patches, DT bindings + IOMMU), v2 (2
patches, simplified to driver + DT dmas)
- Cover letter states Jetson Xavier NX (tegra194/p3668) SPI NOR "would
time out on all transfers and sometimes even trigger a cbb fault,
locking up the entire unit"
- No explicit stable nomination found in thread
- No NAKs found; merged by Mark Brown
**Step 4.2 — Reviewers**
- Record: CC'd to Thierry Reding, Jonathan Hunter, Sowjanya Komatineni,
Mark Brown, linux-tegra, linux-spi, devicetree lists.
**Step 4.3 — Bug report details**
- Record:
- Cover letter documents real hardware failure: SPI NOR timeouts and
CBB faults on Jetson Xavier NX.
- Severity from reporter: system lockups (CRITICAL class).
- Full fix requires patch 2/2 (DT DMA properties) plus this driver fix
for correct DMA engine device usage.
**Step 4.4 — Related patches**
- Record:
- Patch 2/2: `arm64: tegra: Enable DMA Support on Tegra194 QSPI` —
adds `dmas = <&gpcdma 5>` to tegra194 QSPI nodes.
- Sashiko AI review flagged pre-existing driver issues exposed by
enabling DMA (unmap-on-error path, packed-mode buffer rounding);
those are separate from this commit.
**Step 4.5 — Stable list history**
- Record: No stable-list discussion found for this specific SPI patch.
(Lore direct fetch blocked by bot protection; b4 mbox used instead.)
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
- Record: `tegra_qspi_init_dma()`, `tegra_qspi_deinit_dma()`,
`tegra_qspi_dma_map_xfer()`, `tegra_qspi_dma_unmap_xfer()`,
`tegra_qspi_start_dma_based_transfer()` (caller)
**Step 5.2 — Callers**
- Record:
- `tegra_qspi_init_dma()` called from probe (`~line 1693`) during
device initialization.
- `tegra_qspi_dma_map_xfer()` called from
`tegra_qspi_start_dma_based_transfer()` for packed transfers.
- DMA transfers triggered from `tegra_qspi_setup_transfer_one()` when
`use_dma && total_fifo_words > QSPI_FIFO_DEPTH`.
- Reachable on every large SPI transfer on DMA-enabled platforms.
**Step 5.3 — Callees**
- Record: `dma_request_chan()`, `dmaengine_get_dma_device()`,
`dma_alloc_coherent()`, `dma_map_single()`,
`dmaengine_slave_config()`, `dmaengine_prep_slave_single()`.
**Step 5.4 — Call chain / reachability**
- Record:
- Probe → `tegra_qspi_init_dma()` → DMA buffer allocation (boot/init
path).
- Userspace SPI ioctl → `spi_sync()` → controller transfer → DMA path
for large transfers.
- **Userspace-reachable** on platforms with external DMA enabled
(tegra210 has `dmas` in DT; tegra194 will once patch 2 lands).
**Step 5.5 — Similar patterns**
- Record: Identical fix already applied in this tree for `i2c-tegra.c`
(`cdbf26251d3b3`), which explicitly documents SMMU stream-ID
misconfiguration without the fix. Other drivers in tree use
`dmaengine_get_dma_device()` (e.g., `j721e-csi2rx`, `k3-udma`).
---
## Phase 6: Cross-Referencing Against Local Tree (6.18.44)
**Step 6.1 — Does buggy code exist?**
- Record: **Yes.** Current `spi-tegra210-quad.c` uses `tqspi->dev` for
all DMA API calls (lines 577–810). No `rx_dma_dev`/`tx_dma_dev` fields
exist. Bug present since driver introduction (2020).
**Step 6.2 — Backport complications**
- Record: **Clean apply** — cherry-pick auto-merges with no conflicts
(18 insertions, 11 deletions).
**Step 6.3 — Related fixes already present?**
- Record: `i2c: tegra: Allocate DMA memory for DMA engine`
(`cdbf26251d3b3`) is already in 6.18.y. No equivalent SPI fix yet.
This SPI commit is NOT in HEAD.
**Platform-specific notes for this tree:**
| Platform | `has_ext_dma` | DMA in DT (6.18.44) | Bug path active? |
|----------|---------------|---------------------|------------------|
| tegra210 | true | Yes (`apbdma`) | Yes — external DMA used today |
| tegra186/194 | true | No (194 lacks `dmas`) | No — falls back to PIO
before DMA alloc |
| tegra234 | false | N/A (internal DMA) | No behavior change from fix |
| tegra241 | true | No DT in tree yet | N/A currently |
---
## Phase 7: Subsystem and Maintainer Context
**Step 7.1 — Subsystem criticality**
- Record: `drivers/spi/` — IMPORTANT (peripheral driver), but DMA/IOMMU
correctness on embedded Tegra hardware with SPI flash boot/storage.
**Step 7.2 — Subsystem activity**
- Record: Actively maintained — recent 6.18.y commits include timeout
handling, `curr_xfer` race fixes, internal DMA support
(`017f1b0bae08e`).
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
- Record: Tegra platforms using external DMA for QSPI — tegra210 today;
tegra194/241 once DT enables GPCDMA. Jetson Xavier NX (p3668) is the
documented failing platform for the companion DT patch.
**Step 8.2 — Trigger conditions**
- Record:
- External DMA path active (`has_ext_dma=true`, DMA channels
successfully requested, `use_dma=true`).
- Large SPI transfers exceeding FIFO depth.
- Most impactful when IOMMU/SMMU separates DMA engine and controller
stream IDs (tegra194 with GPCDMA).
- Unprivileged users can trigger via SPI device access.
**Step 8.3 — Failure mode severity**
- Record:
- IOMMU faults (CBB faults mentioned in cover letter) — **CRITICAL**
- SPI transfer timeouts / hangs — **CRITICAL**
- Potential buffer corruption with wrong mappings — **HIGH**
- On tegra210 without IOMMU: bug may be latent (mappings may work by
accident) — lower practical severity there.
**Step 8.4 — Risk-benefit**
- Record:
- **Benefit:** HIGH for tegra194 DMA enablement; MEDIUM for tegra210;
enables correct external DMA operation matching established
i2c-tegra precedent.
- **Risk:** VERY LOW — 29-line single-file change, proven API, no-op
for internal-DMA path.
- **Ratio:** Strong benefit, minimal risk.
---
## Phase 9: Final Synthesis
**Evidence FOR backport:**
- Real DMA/IOMMU correctness bug with established kernel precedent
(i2c-tegra fix already in 6.18.y).
- Required prerequisite for tegra194 DMA enablement fixing Jetson Xavier
NX SPI NOR timeouts and CBB faults.
- tegra210 already uses external DMA with buggy device pointer today.
- Small, surgical, applies cleanly.
- Maintainer-reviewed and merged (Mark Brown; suggested by Thierry
Reding).
- Prevents IOMMU faults, hangs, and potential data corruption.
**Evidence AGAINST backport:**
- Alone does not enable tegra194 DMA (needs companion DT patch 2/2).
- On current 6.18.44 tegra194 configs, driver falls back to PIO (no
`dmas` in DT) — this specific commit doesn't fix the documented Xavier
NX timeout by itself.
- tegra234 (internal DMA) unaffected.
- No syzbot report or explicit user `Reported-by:` in commit message.
**Unresolved questions:**
- Exact practical impact on tegra210 without IOMMU is unverified (may be
latent).
- Pre-existing driver issues flagged by Sashiko review when DMA is
enabled are separate bugs.
**Stable rules checklist:**
1. Obviously correct and tested? **PASS** — mirrors accepted i2c-tegra
fix; API well-established.
2. Fixes a real bug affecting users? **PASS** — DMA engine device
mismatch is a real bug; tegra210 affected now, tegra194 when DMA
enabled.
3. Important issue? **PASS** — IOMMU faults, system lockups, transfer
failures (CRITICAL/HIGH).
4. Small and contained? **PASS** — 29 lines, one file.
5. No new features or APIs? **PASS** — bug fix only.
6. Can apply to local tree? **PASS** — verified clean cherry-pick.
**Exception category:** Not a device-ID/quirk/DT-only fix; this is a
driver DMA correctness bug fix.
---
## Problem Summary
The tegra210-quad SPI driver allocates and maps DMA buffers using the
SPI controller's `struct device`, but when `has_ext_dma` is true, an
external DMA engine (GPCDMA on tegra194/241, APBDMA on tegra210)
performs the actual memory accesses. The DMA API must use the DMA
engine's device so IOMMU mappings and DMA operations match the hardware
master doing the transfer.
Without this fix, enabling external DMA (as done in the companion
tegra194 DT patch) can cause IOMMU faults, SPI transfer failures,
timeouts, and system lockups — exactly what the series cover letter
documents for Jetson Xavier NX SPI NOR flash.
For 6.18.44 users, tegra210 platforms with `dmas` in DT already exercise
the buggy path. The fix is a necessary prerequisite before tegra194 DMA
can work correctly.
## Verification
- [Phase 1] `git describe HEAD` → `v6.18.44`; parsed commit message tags
and body from provided diff and `git show f469138a77ac5`
- [Phase 2] Read current `spi-tegra210-quad.c` lines 568–818; confirmed
all DMA API calls use `tqspi->dev`
- [Phase 3] `git blame` lines 577/801 → introduced in `921fc1838fb036`
(2020); `017f1b0bae08e` added `has_ext_dma`; `git merge-base --is-
ancestor f469138a77ac5 HEAD` → NOT in HEAD
- [Phase 3] `git cherry-pick --no-commit f469138a77ac5` → exit 0, clean
auto-merge
- [Phase 4] `b4 dig -c f469138a77ac5` → lore URL found; `b4 dig -a` →
v1/v2 series; `b4 dig -m` → cover letter documents Xavier NX
timeouts/CBB faults
- [Phase 4] `b4 dig -w` → Mark Brown, Thierry Reding, linux-tegra CC'd
- [Phase 5] Traced call chain: probe → `tegra_qspi_init_dma()`; transfer
→ `tegra_qspi_start_dma_based_transfer()` →
`tegra_qspi_dma_map_xfer()`
- [Phase 5] `grep dmaengine_get_dma_device` → API present in
`include/linux/dmaengine.h:1672`
- [Phase 6] `grep rx_dma_dev` in driver → no matches (fix absent);
tegra210 DT has `dmas` at `tegra210.dtsi:1883`; tegra194 QSPI nodes
lack `dmas` at `tegra194.dtsi:921-932`
- [Phase 6] `git log stable/linux-6.18.y --grep='Allocate DMA memory' --
i2c-tegra.c` → `cdbf26251d3b3` present
- [Phase 8] Cover letter: "time out on all transfers... cbb fault,
locking up the entire unit"
- UNVERIFIED: Practical tegra210 impact without IOMMU (no IOMMU property
in tegra210 QSPI DT)
**YES**The background search finished and matches what the full review
already found.
**Commit:** `f469138a77ac5` — `spi: tegra210-quad: Allocate DMA memory
for DMA engine`
**Tree:** `v6.18.44` (`stable/linux-6.18.y`) — the fix is **not** in
this tree yet, but it cherry-picks cleanly.
**What it does:** Uses the external DMA engine’s `struct device` (via
`dmaengine_get_dma_device()`) for DMA map/alloc/unmap instead of the SPI
controller device — same pattern as the existing `i2c: tegra` fix
already in 6.18.y.
**Why it matters:** Needed for correct external DMA on Tegra QSPI
(tegra210 today; tegra194 once DMA is enabled in DT). Without it, you
can get IOMMU faults, transfer failures, and hangs — the Jetson Xavier
NX SPI NOR issue from the patch series.
**Verdict: YES** for backport to 6.18.y.
drivers/spi/spi-tegra210-quad.c | 29 ++++++++++++++++++-----------
1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index 83def82fe48c1..543f13503df3d 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -226,11 +226,13 @@ struct tegra_qspi {
struct completion xfer_completion;
struct spi_transfer *curr_xfer;
+ struct device *rx_dma_dev;
struct dma_chan *rx_dma_chan;
u32 *rx_dma_buf;
dma_addr_t rx_dma_phys;
struct dma_async_tx_descriptor *rx_dma_desc;
+ struct device *tx_dma_dev;
struct dma_chan *tx_dma_chan;
u32 *tx_dma_buf;
dma_addr_t tx_dma_phys;
@@ -574,15 +576,15 @@ static int tegra_qspi_dma_map_xfer(struct tegra_qspi *tqspi, struct spi_transfer
len = DIV_ROUND_UP(tqspi->curr_dma_words * tqspi->bytes_per_word, 4) * 4;
if (t->tx_buf) {
- t->tx_dma = dma_map_single(tqspi->dev, (void *)tx_buf, len, DMA_TO_DEVICE);
- if (dma_mapping_error(tqspi->dev, t->tx_dma))
+ t->tx_dma = dma_map_single(tqspi->tx_dma_dev, (void *)tx_buf, len, DMA_TO_DEVICE);
+ if (dma_mapping_error(tqspi->tx_dma_dev, t->tx_dma))
return -ENOMEM;
}
if (t->rx_buf) {
- t->rx_dma = dma_map_single(tqspi->dev, (void *)rx_buf, len, DMA_FROM_DEVICE);
- if (dma_mapping_error(tqspi->dev, t->rx_dma)) {
- dma_unmap_single(tqspi->dev, t->tx_dma, len, DMA_TO_DEVICE);
+ t->rx_dma = dma_map_single(tqspi->rx_dma_dev, (void *)rx_buf, len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(tqspi->rx_dma_dev, t->rx_dma)) {
+ dma_unmap_single(tqspi->tx_dma_dev, t->tx_dma, len, DMA_TO_DEVICE);
return -ENOMEM;
}
}
@@ -597,9 +599,9 @@ static void tegra_qspi_dma_unmap_xfer(struct tegra_qspi *tqspi, struct spi_trans
len = DIV_ROUND_UP(tqspi->curr_dma_words * tqspi->bytes_per_word, 4) * 4;
if (t->tx_buf)
- dma_unmap_single(tqspi->dev, t->tx_dma, len, DMA_TO_DEVICE);
+ dma_unmap_single(tqspi->tx_dma_dev, t->tx_dma, len, DMA_TO_DEVICE);
if (t->rx_buf)
- dma_unmap_single(tqspi->dev, t->rx_dma, len, DMA_FROM_DEVICE);
+ dma_unmap_single(tqspi->rx_dma_dev, t->rx_dma, len, DMA_FROM_DEVICE);
}
static int tegra_qspi_start_dma_based_transfer(struct tegra_qspi *tqspi, struct spi_transfer *t)
@@ -745,7 +747,7 @@ static int tegra_qspi_start_cpu_based_transfer(struct tegra_qspi *qspi, struct s
static void tegra_qspi_deinit_dma(struct tegra_qspi *tqspi)
{
if (tqspi->tx_dma_buf) {
- dma_free_coherent(tqspi->dev, tqspi->dma_buf_size,
+ dma_free_coherent(tqspi->tx_dma_dev, tqspi->dma_buf_size,
tqspi->tx_dma_buf, tqspi->tx_dma_phys);
tqspi->tx_dma_buf = NULL;
}
@@ -756,7 +758,7 @@ static void tegra_qspi_deinit_dma(struct tegra_qspi *tqspi)
}
if (tqspi->rx_dma_buf) {
- dma_free_coherent(tqspi->dev, tqspi->dma_buf_size,
+ dma_free_coherent(tqspi->rx_dma_dev, tqspi->dma_buf_size,
tqspi->rx_dma_buf, tqspi->rx_dma_phys);
tqspi->rx_dma_buf = NULL;
}
@@ -782,6 +784,7 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
}
tqspi->rx_dma_chan = dma_chan;
+ tqspi->rx_dma_dev = dmaengine_get_dma_device(tqspi->rx_dma_chan);
dma_chan = dma_request_chan(tqspi->dev, "tx");
if (IS_ERR(dma_chan)) {
@@ -790,15 +793,19 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
}
tqspi->tx_dma_chan = dma_chan;
+ tqspi->tx_dma_dev = dmaengine_get_dma_device(tqspi->tx_dma_chan);
} else {
if (!device_iommu_mapped(tqspi->dev)) {
dev_warn(tqspi->dev,
"IOMMU not enabled in device-tree, falling back to PIO mode\n");
return 0;
}
+
+ tqspi->rx_dma_dev = tqspi->dev;
+ tqspi->tx_dma_dev = tqspi->dev;
}
- dma_buf = dma_alloc_coherent(tqspi->dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
+ dma_buf = dma_alloc_coherent(tqspi->rx_dma_dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
if (!dma_buf) {
err = -ENOMEM;
goto err_out;
@@ -807,7 +814,7 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
tqspi->rx_dma_buf = dma_buf;
tqspi->rx_dma_phys = dma_phys;
- dma_buf = dma_alloc_coherent(tqspi->dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
+ dma_buf = dma_alloc_coherent(tqspi->tx_dma_dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
if (!dma_buf) {
err = -ENOMEM;
goto err_out;
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH AUTOSEL 6.18-6.1] spi: xilinx: let transfers timeout in case of no IRQ
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (5 preceding siblings ...)
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18] spi: tegra210-quad: Allocate DMA memory for DMA engine Sasha Levin
@ 2026-08-31 13:27 ` Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18] spi: spi-nxp-fspi: enter stop mode before reconfiguring MCR0 and DLL Sasha Levin
` (2 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2026-08-31 13:27 UTC (permalink / raw)
To: patches, stable
Cc: Vadim Fedorenko, Michal Simek, Mark Brown, Sasha Levin, linux-spi,
linux-arm-kernel, linux-kernel
From: Vadim Fedorenko <vadim.fedorenko@linux.dev>
[ Upstream commit 0f95264f49ace739d411fd9149e2b3545d741d06 ]
In case of failed HW the driver may not see an interrupt and will stuck
in waiting forever. We can avoid such situation by timing out of
transfers if the interrupt is not seen in a reasonable time.
This problem can be found on unload of ptp_ocp driver for TimeCard which
uses Xilinx SPI AXI and SPI-NOR flash memory. During tear-down process
spi-nor drivers send soft reset command which is not triggering an
interrupt stalling the unload process completely.
Signed-off-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Acked-by: Michal Simek <michal.simek@amd.com>
Link: https://patch.msgid.link/20260610222843.782337-1-vadim.fedorenko@linux.dev
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `spi: xilinx: let transfers timeout in case
of no IRQ`
**Local tree:** `v6.18.44-1-g2736c32da98b9` (linux-6.18.y stable)
**Commit under review:** `0f95264f49ace` (mainline; **not** in this tree
yet)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject Line
**Record:** `[spi: xilinx]` `[let]` — Add transfer timeout when IRQ-
based completion never arrives.
### Step 1.2: Tags
**Record:**
- **Signed-off-by:** Vadim Fedorenko `<vadim.fedorenko@linux.dev>`
(author)
- **Acked-by:** Michal Simek `<michal.simek@amd.com>` (Xilinx/AMD
maintainer)
- **Link:** https://patch.msgid.link/20260610222843.782337-1-
vadim.fedorenko@linux.dev
- **Signed-off-by:** Mark Brown `<broonie@kernel.org>` (subsystem
maintainer, committer)
- No Fixes:, Reported-by:, Tested-by:, Cc: stable, or syzbot tags
- Notable: maintainer Ack from Xilinx/AMD; no user/fuzzer report, but
concrete hardware scenario described
### Step 1.3: Body Analysis
**Record:**
- **Bug:** In IRQ transfer mode, if the TX-empty interrupt never fires,
`wait_for_completion()` blocks forever.
- **Symptom:** Complete hang during `ptp_ocp` driver unload on TimeCard
hardware (Xilinx SPI AXI + SPI-NOR). During teardown, spi-nor sends a
soft reset that does not trigger an interrupt, stalling unload
indefinitely.
- **Root cause:** IRQ path has no timeout; polling path already has
stall detection (added in 2017).
- **Version info:** None explicit; bug predates `force_irq` (2023) but
is exposed by it.
### Step 1.4: Hidden Bug Fix?
**Record:** No — this is an explicit bug fix for an infinite-wait hang,
not disguised cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **Files:** `drivers/spi/spi-xilinx.c` (+5 / -1)
- **Function:** `xilinx_spi_txrx_bufs()`
- **Scope:** Single-file surgical fix in IRQ transfer path
### Step 2.2: Code Flow Change
**Record:**
- **Hunk (IRQ path, ~line 288):**
- **Before:** `wait_for_completion(&xspi->done)` — blocks forever if
IRQ never arrives
- **After:** `wait_for_completion_timeout(&xspi->done,
secs_to_jiffies(1))` — on timeout: log error, call
`xspi_init_hw(xspi)`, return `-ETIMEDOUT`
- **Path affected:** IRQ-based SPI transfers (`use_irq == true`),
entered when `xspi->irq >= 0` and (`force_irq` or `remaining_words >
buffer_size`)
### Step 2.3: Bug Mechanism
**Record:**
- **Category:** Logic/correctness — missing timeout on blocking wait
(hang/deadlock class)
- **Mechanism:** `xilinx_spi_irq()` calls `complete(&xspi->done)` only
on `XSPI_INTR_TX_EMPTY`. If that IRQ never fires (soft reset during
teardown, failed HW), the caller blocks indefinitely. The polling path
already detects stalls via status-register polling; the IRQ path had
no equivalent safety net.
### Step 2.4: Fix Quality
**Record:**
- **Quality:** High — minimal, follows established SPI subsystem pattern
- **Regression risk:** Very low — 1-second timeout is generous for SPI;
matches `spi.c` core and many other SPI drivers; `xspi_init_hw()` is
already used on stall detection in the same function
- **No red flags:** No API changes, no locking changes, no refactoring
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** `wait_for_completion(&xspi->done)` introduced in
`5fe11cc09ce81b` (Ricardo Ribalda, 2015-01-28, "spi/xilinx: Support
cores with no interrupt"). Bug present since IRQ mode was added — long-
standing in this tree.
### Step 3.2: Fixes: Tag
**Record:** N/A — no Fixes: tag. Bug is inherent to IRQ-path design, not
introduced by a single recent commit.
### Step 3.3: Related File History
**Record:**
- `5a1314fa697fc` (2017): stall detection for polling path — **in
tree**, Cc: stable
- `939edfaa10f1d` (2025): increased stall retry count — **in tree**
- `1dd46599f83ac` (2023): `force_irq` for QSPI — **in tree**, same
author (Fedorenko); forces IRQ path on ptp_ocp TimeCard
- `1c9246a199e19` (2026): FIFO buffer size fix — **in tree** (separate
hang in IRQ mode, already backported)
- Standalone fix, not part of a multi-patch series
### Step 3.4: Author Context
**Record:** Vadim Fedorenko authored `force_irq` for xilinx SPI (2023)
and works on ptp_ocp/TimeCard. Michal Simek (AMD/Xilinx) Acked. Mark
Brown (SPI maintainer) committed.
### Step 3.5: Dependencies
**Record:** No dependencies. `force_irq`, `xspi_init_hw()`,
`wait_for_completion_timeout()`, and `secs_to_jiffies()` all exist in
this tree. Cherry-pick to HEAD auto-merges cleanly.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original Discussion
**Record:**
- **URL:** https://patch.msgid.link/20260610222843.782337-1-
vadim.fedorenko@linux.dev
- **Series:** v1 only (single patch, no revisions)
- **Feedback:** Mark Brown applied to broonie/spi `for-7.2`; Michal
Simek Acked-by in thread
- **No NAKs or objections** found in mbox
- **No explicit Cc: stable** nomination in thread
### Step 4.2: Reviewers
**Record:** CC'd: Mark Brown, Michal Simek, linux-spi@vger.kernel.org.
Subsystem maintainer and Xilinx maintainer both involved.
### Step 4.3: Bug Report
**Record:** No external bug tracker or syzbot report. Bug described from
real hardware (TimeCard/ptp_ocp unload). Severity from reporter:
complete unload hang.
### Step 4.4: Related Patches
**Record:** Related but independent from `1c9246a199e19` (FIFO size IRQ
hang). Both are IRQ-path hang fixes; neither depends on the other.
### Step 4.5: Stable List History
**Record:** No stable-list discussion found for this specific patch.
(WebFetch to lore blocked by bot protection; used b4 mbox download
instead.)
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key Functions
**Record:** `xilinx_spi_txrx_bufs()` (modified), `xilinx_spi_irq()`
(completes wait), `xspi_init_hw()` (recovery on timeout)
### Step 5.2: Callers
**Record:** `xilinx_spi_txrx_bufs` assigned to `xspi->bitbang.txrx_bufs`
at probe; invoked via `spi_bitbang` → `spi_sync()` for all SPI transfers
on this controller. Called from probe, normal I/O, and module-remove
teardown paths.
### Step 5.3: Callees
**Record:** `wait_for_completion_timeout()`, `xspi_init_hw()`,
`dev_err()`, `xspi->write_fn()`/`read_fn()` for register access
### Step 5.4: Call Chain / Reachability
**Record:**
```
rmmod ptp_ocp → spi-nor remove → spi_nor_soft_reset() →
spi_mem_exec_op()
→ spi_sync() → spi_bitbang → xilinx_spi_txrx_bufs() [IRQ path with
force_irq]
→ wait_for_completion() [hangs forever without fix]
```
Reachable from module unload on TimeCard hardware. Also reachable on any
IRQ-mode transfer where HW fails to assert TX-empty interrupt.
### Step 5.5: Similar Patterns
**Record:** Many SPI drivers use `wait_for_completion_timeout(...,
msecs_to_jiffies(1000))` or `secs_to_jiffies(1)`. Core `spi.c` uses
adaptive timeout with `-ETIMEDOUT` return. xilinx was an outlier using
unbounded `wait_for_completion()`.
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE
### Step 6.1: Buggy Code Exists?
**Record:** **Yes.** `drivers/spi/spi-xilinx.c:288` still has
`wait_for_completion(&xspi->done)`. `ptp_ocp.c:702` sets `.force_irq =
true` for TimeCard Xilinx SPI. Bug introduced 2015; exposed on TimeCard
since `force_irq` (2023).
### Step 6.2: Backport Complications
**Record:** Cherry-pick of `0f95264f49ace` onto HEAD succeeds with auto-
merge (tested). Expected: **clean apply**.
### Step 6.3: Related Fixes Already Present?
**Record:** Polling-path stall detection (`5a1314fa697fc`,
`939edfaa10f1d`) and FIFO size fix (`1c9246a199e19`) are in tree. **This
IRQ-timeout fix is not** — grep for "SPI transfer timed out" in spi-
xilinx.c returns nothing.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem Criticality
**Record:** `drivers/spi/` — **IMPORTANT** (peripheral driver, but SPI
core path used by many devices; ptp_ocp is production timing hardware)
### Step 7.2: Subsystem Activity
**Record:** Active — 3 commits to spi-xilinx.c in 2025–2026 in this tree
(stall retries, FIFO fix, cleanups)
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who Is Affected
**Record:** Users of Xilinx SPI in IRQ mode — especially `ptp_ocp`
TimeCard (`force_irq = true`). Also any platform with failed/misbehaving
HW that fails to generate TX-empty IRQ. Config: driver built-in or
module; no special Kconfig beyond SPI + device.
### Step 8.2: Trigger Conditions
**Record:**
- **Primary:** `rmmod ptp_ocp` on TimeCard (soft reset during teardown)
- **Secondary:** Any IRQ-mode transfer where interrupt never fires (HW
failure)
- **Likelihood:** Deterministic on affected hardware during unload; rare
but catastrophic when it hits
- **Unprivileged trigger:** Module unload typically requires
root/CAP_SYS_MODULE
### Step 8.3: Failure Mode Severity
**Record:** **CRITICAL** — unbounded hang (hung task), module cannot be
unloaded, may block reboot/shutdown. Not data corruption, but system
becomes unresponsive for that operation.
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** HIGH — prevents permanent hang on module unload and HW-
failure scenarios
- **Risk:** VERY LOW — 5-line change, established pattern, hardware
reset on timeout matches existing stall recovery
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence Summary
**FOR backporting:**
- Fixes real, reproducible infinite hang on ptp_ocp unload (TimeCard)
- CRITICAL severity (hung task, blocked unload)
- Minimal 5-line fix, obviously correct
- Matches SPI core and peer driver conventions
- Acked by Xilinx maintainer, committed by SPI maintainer
- Buggy code confirmed present in 6.18.44 tree
- Cherry-picks cleanly
- No dependencies, standalone patch
- Complements existing polling-path stall detection (fills IRQ-path gap)
**AGAINST backporting:**
- Affects relatively niche hardware (TimeCard/ptp_ocp with force_irq)
- No syzbot/fuzzer report
- No explicit Cc: stable nomination
- Theoretical false-timeout risk on extremely slow transfers (mitigated
by 1-second timeout, same as rest of SPI subsystem)
**Unresolved:** None that affect the decision.
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — standard timeout pattern;
Acked-by Xilinx maintainer
2. Fixes a real bug affecting users? **PASS** — ptp_ocp unload hang on
TimeCard
3. Important issue? **PASS** — CRITICAL hang on module unload
4. Small and contained? **PASS** — 5 lines, 1 file
5. No new features or APIs? **PASS** — error-path safety only
6. Can apply to local tree? **PASS** — cherry-pick auto-merges
### Step 9.3: Exception Categories
**Record:** N/A — standard bug fix, not device ID/quirk/DT/build/docs
exception.
### Step 9.4: Decision Rationale
For **linux-6.18.y**, the IRQ-path infinite wait is a real bug with a
concrete trigger on hardware this tree supports (`ptp_ocp` +
`force_irq`). Without the fix, `rmmod` hangs forever. The fix is
minimal, follows established SPI patterns, resets hardware on timeout
(same as existing stall path), and applies cleanly. This meets all
stable kernel criteria.
---
## Verification
- [Phase 1] `git show 0f95264f49ace`: parsed full commit message and
tags
- [Phase 1] Acked-by Michal Simek confirmed in commit and mbox
- [Phase 2] `git show 0f95264f49ace -p`: verified +5/-1 diff in
`xilinx_spi_txrx_bufs()`
- [Phase 2] Read `drivers/spi/spi-xilinx.c:238-336`: confirmed IRQ vs
polling paths and existing stall handling
- [Phase 3] `git blame -L 286,292 drivers/spi/spi-xilinx.c`:
`wait_for_completion` from 2015 (`5fe11cc09ce81b`)
- [Phase 3] `git log --oneline -20 -- drivers/spi/spi-xilinx.c`: related
stall/FIFO/force_irq commits identified
- [Phase 3] `git merge-base --is-ancestor`: `5a1314fa697fc`,
`1dd46599f83ac`, `939edfaa10f1d` confirmed in HEAD; `0f95264f49ace`
NOT in HEAD
- [Phase 4] `b4 dig -c 0f95264f49ace -w`: recipients Mark Brown, Michal
Simek, linux-spi
- [Phase 4] `b4 dig -c 0f95264f49ace -a`: single v1 patch, no revisions
- [Phase 4] `b4 dig -c 0f95264f49ace -m /tmp/spi-xilinx-timeout.mbx`:
downloaded thread; Mark Brown applied, Michal Simek Acked, no NAKs
- [Phase 5] Read `drivers/ptp/ptp_ocp.c:693-707`: confirmed `.force_irq
= true` for TimeCard Xilinx SPI
- [Phase 5] Read `drivers/mtd/spi-nor/core.c:3282-3304`: confirmed
`spi_nor_soft_reset()` during remove path
- [Phase 5] Grep `wait_for_completion_timeout` in `drivers/spi/`: many
drivers use 1-second timeout pattern
- [Phase 5] Read `drivers/spi/spi.c:1463-1471`: core SPI layer uses
timeout + `-ETIMEDOUT`
- [Phase 6] `git describe HEAD`: v6.18.44 (linux-6.18.y)
- [Phase 6] Grep `wait_for_completion` in spi-xilinx.c: buggy line at
:288 confirmed
- [Phase 6] Grep "SPI transfer timed out" in tree: only in spi.c, not
spi-xilinx.c (fix not present)
- [Phase 6] `git cherry-pick --no-commit 0f95264f49ace`: auto-merge
succeeded; reset afterward
- [Phase 8] Failure mode: infinite hang on IRQ-path transfer without
interrupt — severity CRITICAL
**YES**
drivers/spi/spi-xilinx.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 8085571913c8b..dac6c695f0727 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -285,7 +285,11 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
if (use_irq) {
xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
- wait_for_completion(&xspi->done);
+ if (!wait_for_completion_timeout(&xspi->done, secs_to_jiffies(1))) {
+ dev_err(&spi->dev, "SPI transfer timed out\n");
+ xspi_init_hw(xspi);
+ return -ETIMEDOUT;
+ }
/* A transmit has just completed. Process received data
* and check for more data to transmit. Always inhibit
* the transmitter while the Isr refills the transmit
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH AUTOSEL 6.18] spi: spi-nxp-fspi: enter stop mode before reconfiguring MCR0 and DLL
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (6 preceding siblings ...)
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18-6.1] spi: xilinx: let transfers timeout in case of no IRQ Sasha Levin
@ 2026-08-31 13:28 ` Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.1] spi: dw-dma: Wait for controller idle before completing Tx Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18] spi: spi-nxp-fspi: propagate clock reconfig failures in nxp_fspi_select_mem() Sasha Levin
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2026-08-31 13:28 UTC (permalink / raw)
To: patches, stable
Cc: Haibo Chen, Frank Li, Mark Brown, Sasha Levin, han.xu, linux-spi,
imx, linux-kernel
From: Haibo Chen <haibo.chen@nxp.com>
[ Upstream commit b4bde5cfff8e43e948219f0a598e4bf057ecfba4 ]
In nxp_fspi_select_mem() the RX sample clock source (MCR0[RXCLKSRC])
and the DLL control registers (DLLxCR) are reconfigured while the
FlexSPI module is still enabled. According to the FlexSPI reference
manual initialization sequence, MCR0 and the DLL control registers
should be programmed while the module is in stop mode, i.e. with
MCR0[MDIS] set to 1, and the module re-enabled (MCR0[MDIS] = 0)
afterwards.
Wrap the RX sample clock source selection and the DLL calibration/
override reconfiguration in a stop-mode window to align with the RM
and avoid reconfiguring timing-critical registers while the module is
active.
Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260728-fspi-clock-v2-2-dbe786a4a6eb@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `spi: spi-nxp-fspi: enter stop mode before
reconfiguring MCR0 and DLL`
**Local tree:** Linux 6.18.44 (`v6.18.44-2-g1b9e1abadee04`, Makefile
`VERSION=6 PATCHLEVEL=18 SUBLEVEL=44`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1 – Subject line**
Record: `[spi: spi-nxp-fspi]` `[enter/align]` — Enter FlexSPI stop mode
(MCR0[MDIS]=1) before reprogramming MCR0 RX clock source and DLL control
registers during runtime memory selection.
**Step 1.2 – Tags**
| Tag | Value |
|-----|-------|
| Signed-off-by | Haibo Chen \<haibo.chen@nxp.com\> |
| Reviewed-by | Frank Li \<Frank.Li@nxp.com\> (NXP) |
| Link | https://patch.msgid.link/20260728-fspi-
clock-v2-2-dbe786a4a6eb@nxp.com |
| Signed-off-by | Mark Brown \<broonie@kernel.org\> (SPI maintainer) |
Notable: No Reported-by, Fixes:, Cc: stable, or syzbot tags. Reviewed by
NXP engineer. Link indicates patch **2/2** of `fspi-clock-v2` series
(patch 1 is already in this tree as `51c52e493346f`).
Record: Reviewed-by from NXP; part of v2 series; no user/fuzzer bug
report in message.
**Step 1.3 – Body analysis**
Record:
- **Bug:** `nxp_fspi_select_mem()` reprograms MCR0[RXCLKSRC] and DLLxCR
while FlexSPI is still enabled (MCR0[MDIS]=0), violating the FlexSPI
reference manual initialization sequence.
- **Symptom:** Timing-critical registers changed while the module is
active; can cause unreliable flash reads when switching chip-select,
DTR/STR mode, or clock rate.
- **Root cause:** Runtime reconfiguration path omits the stop-mode
window that probe initialization already uses correctly.
- **Version info:** None in message.
**Step 1.4 – Hidden bug fix?**
Record: **Yes.** Although framed as RM compliance, this is a hardware
correctness bug fix. The driver’s own probe path already disables the
module (MDIS) before DLL programming; `select_mem()` was inconsistent,
creating a real stability risk on flash access paths.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1 – Inventory**
Record:
- **File:** `drivers/spi/spi-nxp-fspi.c` (+14 lines net in
`nxp_fspi_select_mem()`)
- **Function modified:** `nxp_fspi_select_mem()`
- **Scope:** Single-file, surgical fix
**Step 2.2 – Code flow change**
Record:
- **Hunk 1 (before RX/DLL reconfig):** Reads MCR0, sets MDIS (stop
mode), then proceeds with `nxp_fspi_select_rx_sample_clk_source()`,
clock rate change, and DLL calibration/override.
- **Hunk 2 (after DLL reconfig):** Clears MDIS to re-enable the module.
- **Before:** MCR0 and DLL registers written while module active.
- **After:** Same operations wrapped in stop-mode window, matching probe
init at lines 1244–1252.
**Step 2.3 – Bug mechanism**
Record: **Category (g) logic/correctness + hardware workaround.**
Reprogramming timing-critical MCR0/DLL registers on a live FlexSPI
controller violates documented hardware sequencing. The probe path
already does this correctly; runtime `select_mem()` did not.
**Step 2.4 – Fix quality**
Record:
- **Obviously correct:** Yes — mirrors existing probe/cleanup MDIS usage
in the same file.
- **Minimal:** Yes — ~14 lines, no refactoring.
- **Regression risk:** Low overall. **Minor concern:** pre-existing
early `return` on `clk_set_rate()` / `clk_prep_enable()` failure would
now leave MDIS=1 (module disabled). These paths existed before; stop
mode makes failure state slightly worse, but `clk_set_rate()` failure
is rare and the function already had unsafe early returns.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1 – Blame**
Record: Lines 899–929 in current tree blame to `10eaa4c4a2579` (tree
import artifact; entire `spi-nxp-fspi.c` arrived with stable tree). The
runtime reconfiguration path without stop mode has been present since
the driver exists in this tree.
**Step 3.2 – Fixes: tag**
Record: N/A — no Fixes: tag in commit message.
**Step 3.3 – Related file history**
Record:
- `51c52e493346f` — v2-1 per-SoC rate limits (already in tree; does
**not** include stop mode)
- `40ad64ac25bb7` — ACPI fwnode propagation
- No stop-mode fix already present
**Step 3.4 – Author context**
Record: Haibo Chen (NXP) authored both `51c52e493346f` (v2-1) and this
v2-2 patch. Frank Li (NXP) reviewed. Mark Brown (SPI maintainer)
committed.
**Step 3.5 – Dependencies**
Record: Part of `fspi-clock-v2` 2-patch series. **v2-1 is already in
this tree.** This patch is standalone — it only wraps existing
reconfiguration in stop mode and does not depend on v2-1’s data
structures. Can apply cleanly to current `nxp_fspi_select_mem()`.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1 – Original discussion**
Record: **UNVERIFIED** — `b4 dig -c` could not run (commit not in tree);
lore.kernel.org and patch.msgid.link returned 403/bot protection. Link
confirms patch `fspi-clock-v2-2` from NXP.
**Step 4.2 – Reviewers**
Record: **UNVERIFIED** via b4 dig -w. Commit message shows Reviewed-by:
Frank Li (NXP), Signed-off-by: Mark Brown (SPI maintainer).
**Step 4.3 – Bug report**
Record: No Reported-by or syzbot link. Bug inferred from RM requirement
and inconsistency with probe init.
**Step 4.4 – Series context**
Record: `fspi-clock-v2` series:
- v2-1 (`51c52e493346f`) — per-SoC SDR/DTR limits — **in tree**
- v2-2 (this commit) — stop mode before MCR0/DLL reconfig — **not in
tree**
**Step 4.5 – Stable list**
Record: **UNVERIFIED** — could not search lore stable archive (403).
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1 – Key functions**
Record: `nxp_fspi_select_mem()` modified; calls
`nxp_fspi_select_rx_sample_clk_source()`, `nxp_fspi_dll_calibration()`,
`nxp_fspi_dll_override()`.
**Step 5.2 – Callers**
Record: `nxp_fspi_select_mem()` called from `nxp_fspi_exec_op()` (line
1121), which is the `spi_mem` exec_op handler — invoked on every SPI
flash memory operation when CS, DTR/STR mode, or frequency changes.
**Step 5.3 – Callees**
Record: `fspi_readl`/`fspi_writel` on MCR0,
`nxp_fspi_select_rx_sample_clk_source()` (writes MCR0 RXCLKSRC),
`clk_set_rate`, `nxp_fspi_dll_calibration()`/`nxp_fspi_dll_override()`
(write DLLACR/DLLBCR).
**Step 5.4 – Reachability**
Record: **Userspace-reachable** via MTD/SPI-NOR flash access on NXP
platforms. Triggered when:
- Switching between chip-selects (multi-flash boards)
- Switching DTR ↔ STR mode (e.g., after `spi_nor_suspend` per driver
comment at line 754)
- Changing operation frequency
**Step 5.5 – Similar patterns**
Record: Probe init (lines 1244–1252) and cleanup (line 1352) already use
`FSPI_MCR0_MDIS`. `select_mem()` was the inconsistent outlier. Driver
comment at lines 749–751 notes DTR mode without proper RXCLKSRC “read
operation may meet issue.”
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE (6.18.44)
**Step 6.1 – Buggy code present?**
Record: **Yes.** Current `nxp_fspi_select_mem()` at lines 899–929
reprograms MCR0/DLL without entering stop mode. Commit is **not** yet
applied.
**Step 6.2 – Backport complications**
Record: **Clean apply expected.** Only adds `u32 reg` and MDIS set/clear
around existing code. No structural conflicts with recent changes.
**Step 6.3 – Related fixes already present?**
Record: **No.** `git log --grep='stop mode'` returns nothing. v2-1 rate
limits are present but stop-mode fix is absent.
---
## PHASE 7: SUBSYSTEM CONTEXT
**Step 7.1 – Subsystem and criticality**
Record: **drivers/spi** — NXP FlexSPI controller
(`CONFIG_SPI_NXP_FLEXSPI`, depends on `ARCH_LAYERSCAPE || ARCH_MXC`).
**IMPORTANT** for NXP embedded (i.MX8, i.MX95, LX2160A) — boot/storage
flash lives on this controller.
**Step 7.2 – Activity**
Record: Active — recent commits `51c52e493346f`, `40ad64ac25bb7` in this
tree.
---
## PHASE 8: IMPACT AND RISK
**Step 8.1 – Who is affected**
Record: **Platform-specific** — NXP i.MX and Layerscape boards using
FlexSPI for SPI-NOR flash (common boot media).
**Step 8.2 – Trigger conditions**
Record: Chip-select switch, DTR/STR mode change, or frequency change
during flash I/O. Moderately common on multi-CS or DTR-capable setups.
Unprivileged users can trigger via normal flash/MTD access.
**Step 8.3 – Failure mode severity**
Record: **Flash read corruption or failures** when timing registers are
reprogrammed on an active controller. Severity: **HIGH** for affected
platforms (silent data corruption risk on NOR flash reads).
**Step 8.4 – Risk/benefit**
Record:
- **Benefit:** HIGH for NXP embedded users — prevents unreliable flash
reads during runtime reconfiguration.
- **Risk:** LOW — small change, matches existing probe pattern, NXP-
reviewed.
- **Ratio:** Strong benefit, low risk.
---
## PHASE 9: FINAL SYNTHESIS
**Evidence FOR backport:**
- Fixes real hardware programming sequence violation
- Probe init already uses stop mode; runtime path was wrong by
comparison
- Can cause flash read instability/corruption on CS/mode/freq switches
- Small (~14 lines), surgical, NXP-reviewed
- Buggy code confirmed present in Linux 6.18.44 tree
- v2-1 prerequisite already in tree; patch applies standalone
- Hardware workaround / correctness fix category
**Evidence AGAINST:**
- No explicit user bug report or syzbot finding
- Platform-specific driver (not universal)
- Early-return error paths could leave MDIS=1 (pre-existing pattern,
rare trigger)
- Mailing list discussion unverified
**Stable rules checklist:**
| Criterion | Result |
|-----------|--------|
| 1. Obviously correct and tested? | **PASS** — matches probe pattern;
NXP-reviewed |
| 2. Fixes real bug affecting users? | **PASS** — RM violation on live
controller during flash ops |
| 3. Important issue? | **PASS** — flash read corruption risk, HIGH for
NXP platforms |
| 4. Small and contained? | **PASS** — single function, ~14 lines |
| 5. No new features/APIs? | **PASS** — sequencing fix only |
| 6. Can apply to local tree? | **PASS** — buggy code present, clean
apply expected |
**Exception category:** Hardware workaround / correctness fix for
timing-critical register programming.
---
## Verification
- [Phase 1] Parsed subject, tags (Reviewed-by Frank Li, Link to v2-2),
body — no Reported-by/syzbot
- [Phase 2] Diff analysis: adds MDIS stop-mode window in
`nxp_fspi_select_mem()`, +14 lines
- [Phase 3] `git blame -L 899,929`: buggy path in current tree; `git log
--oneline -- drivers/spi/spi-nxp-fspi.c`: v2-1 present, stop-mode fix
absent
- [Phase 3] `51c52e493346f` confirmed as v2-1 already in tree; stop mode
not included
- [Phase 3] `git merge-base --is-ancestor f43579ef3500 HEAD`: f43579 NOT
ancestor (stable import), but runtime reconfig code exists
- [Phase 4] b4 dig: commit not in tree, could not run `-c`
- [Phase 4] lore.kernel.org / patch.msgid.link: 403 Forbidden —
**UNVERIFIED** discussion content
- [Phase 5] `nxp_fspi_select_mem()` called from `nxp_fspi_exec_op()`
line 1121 — flash hot path
- [Phase 5] Probe lines 1244–1252 use MDIS before DLL config; cleanup
line 1352 uses MDIS
- [Phase 6] `git describe HEAD`: v6.18.44; buggy code at lines 899–929
confirmed by read
- [Phase 6] `git log --grep='stop mode'`: no matches — fix not yet
applied
- [Phase 7] `CONFIG_SPI_NXP_FLEXSPI` in drivers/spi/Kconfig,
ARCH_MXC/ARCH_LAYERSCAPE
- [Phase 8] Supported SoCs: imx8mm/mp/qxp/dxl/ulp/95, lx2160a (device
table lines 1522–1529)
This is a small, hardware-correctness fix that prevents reprogramming
timing-critical FlexSPI registers while the controller is active — a
documented violation that can cause flash read failures on NXP embedded
platforms. The fix mirrors the probe init sequence already in the
driver, applies cleanly to 6.18.44, and its series prerequisite is
already present.
**YES**The background `git log -S 'select_rx_sample_clk_source'` search
timed out and was killed; it wasn’t needed for the verdict — the
relevant history was already covered via blame, file log, and reading
the current `nxp_fspi_select_mem()` code.
**Conclusion for Linux 6.18.44:** backport **YES**. The driver
reprograms MCR0/DLL timing registers at runtime without entering stop
mode, while probe init already does — a small hardware-correctness fix
that can affect flash read reliability on NXP i.MX/Layerscape platforms
when switching chip-select, DTR/STR mode, or frequency.
drivers/spi/spi-nxp-fspi.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index 69ab72fff19d2..5cdd14d72c34c 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -867,6 +867,7 @@ static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
unsigned long rate = op->max_freq;
int ret;
uint64_t size_kb;
+ u32 reg;
/*
* Return when following condition all meet,
@@ -896,6 +897,15 @@ static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
dev_dbg(f->dev, "Target device [CS:%x] selected\n", spi_get_chipselect(spi, 0));
+ /*
+ * Per the FlexSPI reference manual (initialization sequence), MCR0 and
+ * the DLL control registers should be configured while the module is in
+ * stop mode (MCR0[MDIS] = 1). Enter stop mode before reconfiguring the
+ * RX sample clock source and the DLL, then exit stop mode afterwards.
+ */
+ reg = fspi_readl(f, f->iobase + FSPI_MCR0);
+ fspi_writel(f, reg | FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0);
+
nxp_fspi_select_rx_sample_clk_source(f, op_is_dtr);
rate = min(f->max_rate, op->max_freq);
@@ -935,6 +945,10 @@ static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
else
nxp_fspi_dll_override(f);
+ /* Exit stop mode now that MCR0 and the DLL have been reconfigured. */
+ reg = fspi_readl(f, f->iobase + FSPI_MCR0);
+ fspi_writel(f, reg & ~FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0);
+
f->pre_op_rate = op->max_freq;
f->selected = spi_get_chipselect(spi, 0);
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH AUTOSEL 6.18-6.1] spi: dw-dma: Wait for controller idle before completing Tx
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (7 preceding siblings ...)
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18] spi: spi-nxp-fspi: enter stop mode before reconfiguring MCR0 and DLL Sasha Levin
@ 2026-08-31 13:28 ` Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18] spi: spi-nxp-fspi: propagate clock reconfig failures in nxp_fspi_select_mem() Sasha Levin
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2026-08-31 13:28 UTC (permalink / raw)
To: patches, stable
Cc: Wang YuWei, Mark Brown, Sasha Levin, linux-spi, linux-kernel
From: Wang YuWei <1973615295@qq.com>
[ Upstream commit 0bcd59706aeda8a5d48ba656bab74cb26f2b423e ]
dw_spi_dma_wait_tx_done() polls dw_spi_dma_tx_busy(), which only checks
DW_SPI_SR_TF_EMPT. An empty TX FIFO merely means the last data word has
been moved into the shift register; the transfer is not complete on the
bus until DW_SPI_SR_BUSY is also cleared. As a result the wait can
return while the controller is still shifting out the final word.
Any caller that tears down or reconfigures the controller right after
the transfer can then lose the tail of the transfer.
The memory-operation path in spi-dw-core.c already waits for both
DW_SPI_SR_BUSY == 0 and DW_SPI_SR_TF_EMPT == 1. Use the same completion
condition in the DMA path so the transfer is guaranteed to be finished
on the bus before the wait returns.
Signed-off-by: Wang YuWei <1973615295@qq.com>
Link: https://patch.msgid.link/tencent_4EA7B5C94669ED4C38A5F6C1C9126E5D9106@qq.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `spi: dw-dma: Wait for controller idle
before completing Tx`
**Local tree:** `v6.18.44` (`stable/linux-6.18.y`, `VERSION = 6`,
`PATCHLEVEL = 18`, `SUBLEVEL = 44`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: PARSE THE SUBJECT LINE
**Record:** `[spi: dw-dma]` `[Wait]` — Ensure the DesignWare SPI DMA TX
completion wait does not return until the controller is fully idle on
the bus.
### Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
**Record:**
- **Fixes:** — not present (expected for manual review)
- **Reported-by:** — none
- **Tested-by:** — none
- **Reviewed-by:** — none
- **Acked-by:** — none
- **Link:** `https://patch.msgid.link/tencent_4EA7B5C94669ED4C38A5F6C1C9
126E5D9106@qq.com`
- **Cc: stable:** — not present (not a negative signal)
- **Signed-off-by:** Wang YuWei `<1973615295@qq.com>` (author)
- **Signed-off-by:** Mark Brown `<broonie@kernel.org>` (SPI subsystem
maintainer)
Notable: maintainer ack via Mark Brown's Signed-off-by; no syzbot/user
bug report.
### Step 1.3: ANALYZE THE COMMIT BODY TEXT
**Record:**
- **Bug:** `dw_spi_dma_tx_busy()` only checks `DW_SPI_SR_TF_EMPT`. TX
FIFO empty means the last word entered the shift register, but the bus
transfer is not finished until `DW_SPI_SR_BUSY` is also clear.
- **Symptom:** `dw_spi_dma_wait_tx_done()` can return early; callers
that tear down or reconfigure the controller immediately afterward can
truncate the final word(s) of a transfer.
- **Root cause:** Incomplete hardware status polling in the DMA TX wait
path.
- **Fix approach:** Match the DMA path to the intended completion
condition: idle only when `TF_EMPT=1` **and** `BUSY=0`.
### Step 1.4: DETECT HIDDEN BUG FIXES
**Record:** Not disguised — this is an explicit correctness bug fix for
premature TX completion, not cleanup or optimization.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: INVENTORY THE CHANGES
**Record:**
- **Files:** `drivers/spi/spi-dw-dma.c` (+2 / -1)
- **Functions modified:** `dw_spi_dma_tx_busy()` only
- **Scope:** Single-file, surgical (3-line hunk)
### Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
**Record:**
- **Hunk (dw_spi_dma_tx_busy):**
- **Before:** `busy = !(SR & TF_EMPT)` — not busy as soon as TX FIFO
is empty.
- **After:** `busy = ((SR & (BUSY|TF_EMPT)) != TF_EMPT)` — busy unless
FIFO is empty **and** controller is not shifting.
- **Path affected:** `dw_spi_dma_wait_tx_done()` polling loop, called
from `dw_spi_dma_transfer()` after DMA submission completes.
### Step 2.3: IDENTIFY THE BUG MECHANISM
**Record:**
- **Category:** Logic / hardware-timing correctness fix
- **Mechanism:** On DW APB SSI, `TF_EMPT` can be set while `BUSY` is
still set (shift register active). Old code treated that state as
"done"; new code correctly keeps waiting.
### Step 2.4: ASSESS THE FIX QUALITY
**Record:**
- **Quality:** Obviously correct from DW SPI status-register semantics.
- **Minimal:** One condition change in one inline helper.
- **Regression risk:** Very low. Worst case is slightly longer wait on
the final word; that is the intended behavior and matches hardware
reality.
- **Note:** Commit body says mem-op path waits for both `BUSY==0` and
`TF_EMPT==1`, but `dw_spi_ctlr_busy()` in `spi-dw-core.c` only tests
`DW_SPI_SR_BUSY`. The DMA fix itself is still correct; the mem-op
comparison is slightly imprecise wording.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: BLAME THE CHANGED LINES
**Record:**
- Blame on current tree (`HEAD`): lines 282–285 introduced in
`5d324e5159d9e` (Nov 2025 merge bringing in `spi-dw-dma.c`).
- Buggy `TF_EMPT`-only check present at `v6.15`, `v6.16`, `v6.17`,
`v6.18`, and current `HEAD`.
### Step 3.2: FOLLOW THE FIXES: TAG
**Record:** No `Fixes:` tag. N/A.
### Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
**Record:**
- Upstream fix: `0bcd59706aeda` (`spi: dw-dma: Wait for controller idle
before completing Tx`)
- Related nearby fix on this tree: `aae4a47073b12` (NULL deref in
timeout error logging — separate issue)
- Standalone one-patch series (v1 only); no series dependency.
### Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
**Record:** Wang YuWei has no other commits in this tree's
`drivers/spi/` history. Mark Brown is SPI maintainer and applied the
patch.
### Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
**Record:** No prerequisites. `git apply --check` of upstream diff
against current `spi-dw-dma.c` succeeds cleanly. Only touches
`dw_spi_dma_tx_busy()`; no dependency on newer refactors.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
**Record:**
- **b4 dig -c 0bcd59706aeda:** https://patch.msgid.link/tencent_4EA7B5C9
4669ED4C38A5F6C1C9126E5D9106@qq.com
- **Revisions (b4 dig -a):** v1 only
- **Review feedback:** Mark Brown reply: "Applied to broonie/spi
for-7.2. Thanks!" No NAKs, no objections, no explicit stable
nomination in thread.
### Step 4.2: CHECK WHO REVIEWED THE PATCH
**Record (b4 dig -w):** To Mark Brown; Cc Jisheng Zhang, `linux-
spi@vger.kernel.org`, `linux-kernel@vger.kernel.org`. Appropriate
maintainer coverage.
### Step 4.3: SEARCH FOR THE BUG REPORT
**Record:** No external bug report, syzbot link, or hardware-specific
reproduction email. Bug rationale is hardware-spec-based code analysis.
### Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
**Record:** Single-patch series; no companion patches required.
### Step 4.5: CHECK STABLE MAILING LIST HISTORY
**Record:** Lore stable search not performed (lore bot protection on
WebFetch). No stable discussion found in downloaded mbox thread.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
**Record:** `dw_spi_dma_tx_busy()` (modified); caller
`dw_spi_dma_wait_tx_done()` (unchanged).
### Step 5.2: TRACE CALLERS
**Record:**
- `dw_spi_dma_wait_tx_done()` ← `dw_spi_dma_transfer()` (line 660)
- `dw_spi_dma_transfer()` ← `dws->dma_ops->dma_transfer` in `spi-dw-
core.c:456`
- `dw_spi_transfer_one()` ← standard SPI controller transfer path during
DMA-mapped transfers
Called during normal SPI DMA message processing, not obscure init-only
code.
### Step 5.3: TRACE CALLEES
**Record:** `dw_readl(dws, DW_SPI_SR)` — hardware status register read
only. No locks, allocations, or API changes.
### Step 5.4: FOLLOW THE CALL CHAIN
**Record:**
`userspace ioctl/write → spidev or kernel SPI client →
spi_sync/spi_async → dw_spi_transfer_one → dw_spi_dma_transfer →
dw_spi_dma_wait_tx_done → dw_spi_dma_tx_busy`
Reachable from userspace via SPI device nodes and from in-kernel SPI
clients (flash, sensors, etc.) on `CONFIG_SPI_DW_DMA` platforms.
### Step 5.5: SEARCH FOR SIMILAR PATTERNS
**Record:** Mem-op wait in `spi-dw-core.c` uses `dw_spi_ctlr_busy()`
(`BUSY` only). DMA path was inconsistent and too eager. No other
instances of the same broken `TF_EMPT`-only pattern found in this file.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
### Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
**Record:** **Yes.** Current `HEAD` at `drivers/spi/spi-dw-
dma.c:282-285`:
```282:285:drivers/spi/spi-dw-dma.c
static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
{
return !(dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_TF_EMPT);
}
```
Present since at least v6.15 in this repository's tags; definitely
present in v6.18.y.
### Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
**Record:** **Clean apply expected.** `git apply --check` of upstream
patch against current file succeeded. No conflicts with `aae4a47073b12`
(different lines). `ctlr` vs `host` rename in other parts of file does
not affect this hunk.
### Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
**Record:** Fix **not** present. `git merge-base --is-ancestor
0bcd59706aeda HEAD` → not an ancestor. Buggy code still at `HEAD`.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
**Record:** `drivers/spi/` — DesignWare SPI DMA driver. **IMPORTANT**:
widely used on embedded SoCs; SPI often backs boot flash, storage, and
sensors.
### Step 7.2: ASSESS SUBSYSTEM ACTIVITY
**Record:** Active in 6.18.y (recent `aae4a47073b12` fix in same file).
`spi-dw-dma.c` is established infrastructure, not brand-new experimental
code in this tree.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: DETERMINE WHO IS AFFECTED
**Record:** Users of DesignWare SPI with DMA enabled
(`CONFIG_SPI_DW_DMA`). Driver-specific but common on ARM/embedded
platforms using DW APB SSI.
### Step 8.2: DETERMINE THE TRIGGER CONDITIONS
**Record:**
- **Trigger:** Any DMA SPI TX transfer where the wait returns after FIFO
empty but before shift register completes.
- **Likelihood:** Real on real hardware — this is documented DW SPI
behavior, not theoretical.
- **Userspace trigger:** Yes, via SPI userspace access or kernel drivers
using DMA-mapped transfers.
### Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
**Record:**
- **Failure mode:** Truncated/lost tail of SPI transfer; possible data
corruption on SPI flash/devices, protocol errors, silent bad data.
- **Severity:** **HIGH** (data integrity / silent corruption), not
merely cosmetic.
### Step 8.4: CALCULATE RISK-BENEFIT RATIO
**Record:**
- **Benefit:** HIGH — prevents real transfer truncation on common
embedded hardware.
- **Risk:** VERY LOW — 2-line status-check correction, maintainer-
reviewed.
- **Ratio:** Strongly favors backport.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: COMPILE THE EVIDENCE
**FOR backport:**
- Real hardware-timing bug with plausible data-corruption impact
- Buggy code confirmed in v6.18.44
- Fix is minimal, obviously correct, applies cleanly
- SPI maintainer (Mark Brown) Signed-off-by
- Affects normal DMA SPI transfer completion path
- No prerequisite commits
**AGAINST backport:**
- No user bug report or syzbot reproduction (weak negative only)
- Commit message slightly overstates mem-op path behavior (does not
affect fix correctness)
**Unresolved:** No hardware-specific reproduction logs; impact inferred
from DW SPI register semantics and code path (sufficient for this class
of driver fix).
### Step 9.2: STABLE RULES CHECKLIST
1. Obviously correct and tested? **PASS** — logic matches hardware;
maintainer applied; no Tested-by but change is trivial and
verifiable.
2. Fixes a real bug affecting users? **PASS** — premature TX completion
can truncate transfers.
3. Important issue? **PASS** — data corruption / transfer integrity
(HIGH).
4. Small and contained? **PASS** — 1 file, 2 lines changed.
5. No new features or APIs? **PASS** — behavior correction only.
6. Can apply to local tree? **PASS** — verified clean apply.
### Step 9.3: EXCEPTION CATEGORIES
**Record:** None (not device ID, quirk, DT, build, or docs). Standard
driver correctness fix.
### Step 9.4: DECISION RATIONALE
For **linux-6.18.y**, the buggy `TF_EMPT`-only wait exists, the fix is
absent, the patch applies cleanly, and the failure mode (truncated SPI
DMA transfers) is materially important for stable users on DW SPI + DMA
platforms. This is exactly the kind of small, hardware-correctness fix
stable trees should carry.
---
## Verification
- [Phase 1] Parsed subject, tags, body; no Fixes/Reported-by/syzbot
- [Phase 2] Diff: 1 file, `dw_spi_dma_tx_busy()` only; logic change
verified
- [Phase 3] `git describe HEAD` → `v6.18.44`; blame → buggy lines at
282–285
- [Phase 3] `git cat-file` / `git grep` → buggy code at v6.15, v6.16,
v6.17, v6.18, HEAD
- [Phase 3] Upstream commit `0bcd59706aeda` confirmed; not ancestor of
HEAD
- [Phase 3] `git apply --check` → patch applies cleanly to current tree
- [Phase 4] `b4 dig -c 0bcd59706aeda` → lore URL found
- [Phase 4] `b4 dig -a` → v1 only
- [Phase 4] `b4 dig -w` → Mark Brown, Jisheng Zhang, linux-spi CC'd
- [Phase 4] mbox thread → Mark Brown applied; no NAKs
- [Phase 5] Call chain traced: `dw_spi_transfer_one` →
`dw_spi_dma_transfer` → `dw_spi_dma_wait_tx_done`
- [Phase 5] `dw_spi_dma_wait_tx_done` called at `spi-dw-dma.c:660` when
`cur_msg->status == -EINPROGRESS`
- [Phase 6] Buggy code read at `spi-dw-dma.c:282-285` on HEAD
- [Phase 6] Related fix `aae4a47073b12` present; this fix not present
- [Phase 8] Failure mode: truncated SPI TX → data corruption risk,
severity HIGH
**YES**
drivers/spi/spi-dw-dma.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
index 31063f9270924..72b85e0f683dc 100644
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -281,7 +281,8 @@ static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed)
static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
{
- return !(dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_TF_EMPT);
+ return (dw_readl(dws, DW_SPI_SR) &
+ (DW_SPI_SR_BUSY | DW_SPI_SR_TF_EMPT)) != DW_SPI_SR_TF_EMPT;
}
static int dw_spi_dma_wait_tx_done(struct dw_spi *dws,
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH AUTOSEL 6.18] spi: spi-nxp-fspi: propagate clock reconfig failures in nxp_fspi_select_mem()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (8 preceding siblings ...)
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.1] spi: dw-dma: Wait for controller idle before completing Tx Sasha Levin
@ 2026-08-31 13:31 ` Sasha Levin
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2026-08-31 13:31 UTC (permalink / raw)
To: patches, stable
Cc: Haibo Chen, Mark Brown, Sasha Levin, han.xu, linux-spi, imx,
linux-kernel
From: Haibo Chen <haibo.chen@nxp.com>
[ Upstream commit b5902b9779796d515b7d65eb9205994b7a8d00cb ]
nxp_fspi_select_mem() disables the FlexSPI clocks before calling
clk_set_rate() and re-enabling them. If clk_set_rate() or the clock
re-enable fails, the function returned early (as void) leaving both the
serial root clock and the register interface clock disabled.
As the function returned void, nxp_fspi_exec_op() had no way to know
about the failure and continued to access FlexSPI registers (LUT setup,
data transfer, AHB buffer invalidation). Accessing the controller
registers while its clock is gated off results in a synchronous external
abort.
Make nxp_fspi_select_mem() return an error code and have
nxp_fspi_exec_op() bail out on failure before any further register
access, including nxp_fspi_invalid().
Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
Link: https://patch.msgid.link/20260728-fspi-clock-v2-3-dbe786a4a6eb@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `spi: spi-nxp-fspi: propagate clock reconfig
failures in nxp_fspi_select_mem()`
**Local tree:** Linux **6.18.44** (`git describe HEAD` →
`v6.18.44-2-g1b9e1abadee04`, Makefile `6.18.44`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: PARSE THE SUBJECT LINE
**Record:** `[spi: spi-nxp-fspi]` `[propagate]` — propagate clock
reconfiguration failures from `nxp_fspi_select_mem()` to its caller.
### Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
**Record:**
- **Fixes:** — none
- **Reported-by:** — none
- **Tested-by:** — none
- **Reviewed-by:** — none
- **Acked-by:** — none
- **Link:** `https://patch.msgid.link/20260728-fspi-
clock-v2-3-dbe786a4a6eb@nxp.com` (PATCH v2 3/3)
- **Cc: stable:** — none (expected for manual review)
- **Signed-off-by:** Haibo Chen `<haibo.chen@nxp.com>`, Mark Brown
`<broonie@kernel.org>` (SPI maintainer)
Notable: part of a 3-patch series; no syzbot/fuzzer report, but
maintainer merge is a quality signal.
### Step 1.3: ANALYZE THE COMMIT BODY TEXT
**Record:**
- **Bug:** `nxp_fspi_select_mem()` disables FlexSPI clocks, calls
`clk_set_rate()`, then re-enables. On `clk_set_rate()` or re-enable
failure, it returns early as `void`, leaving clocks disabled.
- **Symptom:** `nxp_fspi_exec_op()` continues with LUT setup, data
transfer, and `nxp_fspi_invalid()` — register accesses with clocks
gated → **synchronous external abort** (SoC bus fault / kernel crash).
- **Root cause:** Missing error propagation from a `void` helper.
- **Fix:** Return `int` from `nxp_fspi_select_mem()`, re-enable clocks
on `clk_set_rate()` failure (for runtime PM balance), bail out of
`nxp_fspi_exec_op()` before any further register access.
### Step 1.4: DETECT HIDDEN BUG FIXES
**Record:** Not disguised — this is an explicit crash-prevention fix on
an error path, not cosmetic cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: INVENTORY THE CHANGES
**Record:**
- **File:** `drivers/spi/spi-nxp-fspi.c` (~25 insertions, ~7 deletions)
- **Functions:** `nxp_fspi_select_mem()`, `nxp_fspi_exec_op()`
- **Scope:** Single-file, surgical fix
### Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
**Hunk 1 — `nxp_fspi_select_mem()`:**
- **Before:** `static void`; early-exit paths return nothing;
`clk_set_rate()` / `nxp_fspi_clk_prep_enable()` failures silently
return with clocks disabled.
- **After:** `static int`; success returns `0`; `clk_set_rate()` failure
re-enables clocks then returns error; `clk_prep_enable()` failure
returns error; success returns `0`.
**Hunk 2 — `nxp_fspi_exec_op()`:**
- **Before:** Ignores `nxp_fspi_select_mem()` result; always runs
`nxp_fspi_prepare_lut()`, transfer path, and `nxp_fspi_invalid()`.
- **After:** Checks return value; on failure calls
`pm_runtime_put_autosuspend()` and returns immediately — no register
access.
### Step 2.3: IDENTIFY THE BUG MECHANISM
**Record:** **Error-path / memory-mapped I/O safety fix.** Category:
NULL/gated-clock register access leading to synchronous external abort
(ARM-class failure). Mechanism: clocks disabled at lines 912–920 in the
current tree, failure swallowed, MMIO continues.
### Step 2.4: ASSESS THE FIX QUALITY
**Record:**
- Fix is obviously correct and minimal.
- Re-enabling clocks on `clk_set_rate()` failure preserves runtime PM
reference counting — thoughtful detail.
- Low regression risk: only affects already-failing paths.
- On `nxp_fspi_clk_prep_enable()` failure, clocks may still be left
disabled, but caller correctly avoids MMIO (better than crashing).
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: BLAME THE CHANGED LINES
**Record:** In this 6.18.44 tree, the buggy `clk_set_rate()` early-
return pattern at lines 914–920 is present. `git blame` attributes
surrounding code to `10eaa4c4a2579` (bulk import in this checkout; not a
meaningful per-line history). The void-return + silent-failure pattern
is in the current file.
### Step 3.2: FOLLOW THE FIXES: TAG
**Record:** No `Fixes:` tag. N/A.
### Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
**Record:**
- `51c52e493346f` — **already in this tree**: patch 1/3 of the same
series (per-SoC SDR/DTR rate limits), committed by Greg K-H as stable
backport.
- Patch 2/3 (“enter stop mode before reconfiguring MCR0 and DLL”) is
**not** in this tree.
- This fix (patch 3/3) is **not** in this tree.
- Standalone for the error-propagation bug: patch 3 does not require
patch 2; patch 2 is an init-sequence improvement.
### Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
**Record:** Haibo Chen (NXP) authored `51c52e493346f` already backported
here; SPI maintainer Mark Brown committed both.
### Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
**Record:**
- Series context: v2 0/3 cover letter lists patches 1–3; patch 1 is
already present.
- Patch 3 applies cleanly to **this tree's** simpler
`nxp_fspi_select_mem()` (no MCR0 stop-mode hunks from patch 2).
- **Can apply standalone:** YES (minor context adaptation only).
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
**Record:**
- `b4 dig -c <commit>`: commit not in this tree; could not run against
commitish.
- **lkml.iu.edu:** [PATCH v2 3/3] — confirms diff and crash description.
- **lists.openwall.net:** [PATCH v2 0/3] series cover letter — patches
1–3 described; v2 adds patches 2–3 per review feedback.
- lore.kernel.org blocked by bot protection; used lkml/openwall mirrors
instead.
### Step 4.2: CHECK WHO REVIEWED THE PATCH
**Record:** Cover letter To: Han Xu, Yogesh Gaur, **Mark Brown** (SPI
maintainer). Cc: linux-spi, imx, linux-kernel. Mark Brown committed the
patch upstream.
### Step 4.3: SEARCH FOR THE BUG REPORT
**Record:** No external bug report or syzbot link. Bug identified by
code-path analysis in the patch series (v2 added per review). Severity
described authoritatively: synchronous external abort.
### Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
**Record:** 3-patch series; patch 1 backported here; patch 2 optional;
patch 3 is the subject commit.
### Step 4.5: CHECK STABLE MAILING LIST HISTORY
**Record:** Not searched separately; patch 1 already landed in this
6.18.y tree via Greg K-H, indicating the series is stable-appropriate.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
**Record:** `nxp_fspi_select_mem()`, `nxp_fspi_exec_op()`, plus callees
`nxp_fspi_clk_disable_unprep()`, `clk_set_rate()`,
`nxp_fspi_clk_prep_enable()`, `nxp_fspi_prepare_lut()`,
`nxp_fspi_invalid()`.
### Step 5.2: TRACE CALLERS
**Record:** `nxp_fspi_exec_op` is registered in
`nxp_fspi_mem_ops.exec_op` (line 1329). Called from `spi_mem_exec_op()`
in `drivers/spi/spi-mem.c`, which is the standard path for SPI NOR flash
operations (read/program/erase). Common on NXP i.MX and Layerscape
boards using FlexSPI for boot flash.
### Step 5.3: TRACE CALLEES
**Record:** Clock disable/enable (`nxp_fspi_clk_*`), `clk_set_rate()`,
MMIO via `fspi_readl`/`fspi_writel` in LUT prep and `nxp_fspi_invalid()`
(MCR0 SWRESET).
### Step 5.4: FOLLOW THE CALL CHAIN
**Record:** MTD/spi-nor → `spi_mem_exec_op()` → `nxp_fspi_exec_op()` →
`nxp_fspi_select_mem()`. Reachable during normal flash I/O when chip-
select, DTR/STR mode, or `max_freq` changes between operations
(`per_op_freq = true` in mem caps). **Userspace-reachable** via flash
access (root typically, but critical for system stability).
### Step 5.5: SEARCH FOR SIMILAR PATTERNS
**Record:** ACPI path skips manual clock disable/enable
(`is_acpi_node()` early return in `nxp_fspi_clk_disable_unprep` /
`nxp_fspi_clk_prep_enable`). Bug is most severe on **Device Tree**
platforms (primary NXP embedded use case) where
`nxp_fspi_clk_disable_unprep()` actually gates clocks.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
### Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
**Record:** **YES.** Current 6.18.44 code:
```862:920:drivers/spi/spi-nxp-fspi.c
static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device
*spi,
const struct spi_mem_op *op)
{
// ...
nxp_fspi_clk_disable_unprep(f);
ret = clk_set_rate(f->clk, rate);
if (ret)
return;
ret = nxp_fspi_clk_prep_enable(f);
if (ret)
return;
```
```1121:1142:drivers/spi/spi-nxp-fspi.c
nxp_fspi_select_mem(f, mem->spi, op);
nxp_fspi_prepare_lut(f, op);
// ... transfer ...
nxp_fspi_invalid(f);
```
### Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
**Record:** **Clean apply expected.** This tree lacks patch 2's MCR0
stop-mode code in `nxp_fspi_select_mem()`, so the backport is actually
simpler than upstream context. No conflicting changes found.
### Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
**Record:** Patch 1 (`51c52e493346f`) present. This error-propagation
fix is **not** present. No duplicate fix found.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
**Record:** **drivers/spi** — NXP FlexSPI (`CONFIG_SPI_NXP_FLEXSPI`,
depends on `ARCH_MXC || ARCH_LAYERSCAPE`). **IMPORTANT** for embedded
NXP platforms (boot flash, MTD); not universal core code, but critical
where enabled.
### Step 7.2: ASSESS SUBSYSTEM ACTIVITY
**Record:** Active in 6.18.y — recent backports include `51c52e493346f`,
`c1c2871f33360`, `40ad64ac25bb7`.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: DETERMINE WHO IS AFFECTED
**Record:** Users of `CONFIG_SPI_NXP_FLEXSPI` on i.MX
(8MM/MP/QXP/DXL/ULP/95) and Layerscape (LX2160A) platforms with DT-based
clock control.
### Step 8.2: DETERMINE THE TRIGGER CONDITIONS
**Record:** Any SPI-mem operation requiring chip-select or clock/mode
reconfiguration when `clk_set_rate()` or `nxp_fspi_clk_prep_enable()`
fails (unsupported rate, CCM/clock driver error, resource pressure).
Uncommon but realistic; more likely after dynamic per-op frequency
changes. Privileged flash access path.
### Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
**Record:** **Synchronous external abort** on MMIO with gated clocks →
kernel oops/panic. **Severity: CRITICAL.**
### Step 8.4: CALCULATE RISK-BENEFIT RATIO
**Record:**
- **Benefit:** HIGH — prevents hard kernel crash on error path.
- **Risk:** LOW — ~30 lines, error-path only, SPI maintainer committed.
- **Ratio:** Strongly favors backport.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: COMPILE THE EVIDENCE
**FOR backport:**
- Real bug with documented CRITICAL failure mode (sync external abort)
- Small, surgical, maintainer-merged fix
- Buggy code confirmed present in Linux 6.18.44
- Patch 1 of same series already backported to this tree
- Standalone application without patch 2
- Prevents crash on flash I/O error paths
**AGAINST backport:**
- No syzbot/user bug report (theoretical until clock reconfig fails)
- Affects driver-specific embedded platforms only
- Patch 2 of series not in tree (minor context difference, not a
blocker)
**UNRESOLVED:**
- Exact upstream commit SHA not in this checkout (fix not merged here
yet)
- No explicit `Cc: stable` in review thread found
### Step 9.2: STABLE RULES CHECKLIST
1. Obviously correct and tested? **PASS** — logic is clear; merged by
SPI maintainer.
2. Fixes a real bug affecting users? **PASS** — crash on FlexSPI flash
operations.
3. Important issue? **PASS** — CRITICAL (kernel crash / external abort).
4. Small and contained? **PASS** — one file, ~32 lines.
5. No new features or APIs? **PASS** — error propagation only.
6. Can apply to the local tree? **PASS** — bug present; clean/minor-
context apply.
### Step 9.3: EXCEPTION CATEGORIES
**Record:** None (not device ID, quirk, DT, build, or docs). Standard
bug-fix backport.
### Step 9.4: DECISION RATIONALE
For **this 6.18.44 tree**, the buggy void-return pattern is live in
`spi-nxp-fspi.c`. When clock reconfiguration fails during a flash
operation, the driver continues accessing gated FlexSPI registers and
can trigger a synchronous external abort — a production-killing failure
on affected NXP hardware. The fix is minimal, obviously correct, already
vetted by the SPI maintainer, and independently applicable (patch 1 is
already here; patch 2 is not required). Risk is low; benefit is
preventing kernel crashes.
---
## Verification
- **[Phase 1]** `git describe HEAD` → v6.18.44; parsed subject, tags
(Link, SOBs), body
- **[Phase 1]** No Fixes:/Reported-by:/Cc: stable tags
- **[Phase 2]** Read current `spi-nxp-fspi.c` lines 862–934, 1103–1147;
confirmed void return + silent failure
- **[Phase 2]** Confirmed `nxp_fspi_invalid()` does MMIO (lines 611–622)
- **[Phase 2]** Confirmed ACPI skips manual clk disable/enable (lines
704–705, 722–723)
- **[Phase 3]** `git log -20 -- drivers/spi/spi-nxp-fspi.c` — recent
fspi commits
- **[Phase 3]** `git show 51c52e493346f` — patch 1/3 already backported
to this tree
- **[Phase 3]** `git blame -L 900,950` — buggy clk path present
- **[Phase 3]** `git log --grep="propagate clock"` — fix not in tree
- **[Phase 4]** `b4 dig` — commit not in tree; usage confirmed
- **[Phase 4]** WebFetch lkml.iu.edu/2607.3/07703.html — patch 3/3
content confirmed
- **[Phase 4]** WebFetch lists.openwall.net — series cover letter
(patches 1–3) confirmed
- **[Phase 4]** lore.kernel.org — blocked (bot protection); used mirrors
- **[Phase 5]** `grep nxp_fspi_exec_op` — mem_ops registration at line
1329
- **[Phase 5]** Read `spi-mem.c` `spi_mem_exec_op()` — standard flash
path
- **[Phase 5]** Kconfig `SPI_NXP_FLEXSPI` — ARCH_MXC || ARCH_LAYERSCAPE
- **[Phase 5]** `of_device_id` — imx8*, lx2160a, imx95 compatibles
- **[Phase 6]** Buggy code verified present in 6.18.44 checkout
- **[Phase 6]** No duplicate fix in tree
- **[Phase 6]** Patch 2 (MCR0 stop mode) absent — backport simpler
- **[Phase 8]** Failure mode: synchronous external abort — CRITICAL
**YES**
drivers/spi/spi-nxp-fspi.c | 32 +++++++++++++++++++++++++-------
1 file changed, 25 insertions(+), 7 deletions(-)
diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index b504a5c86692a..69ab72fff19d2 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -859,8 +859,8 @@ static void nxp_fspi_dll_override(struct nxp_fspi *f)
* Value for rest of the CS FLSHxxCR0 register would be zero.
*
*/
-static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
- const struct spi_mem_op *op)
+static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
+ const struct spi_mem_op *op)
{
/* flexspi only support one DTR mode: 8D-8D-8D */
bool op_is_dtr = op->cmd.dtr && op->addr.dtr && op->dummy.dtr && op->data.dtr;
@@ -880,7 +880,7 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
if ((f->selected == spi_get_chipselect(spi, 0)) &&
(!!(f->flags & FSPI_DTR_MODE) == op_is_dtr) &&
(f->pre_op_rate == op->max_freq))
- return;
+ return 0;
/* Reset FLSHxxCR0 registers */
fspi_writel(f, 0, f->iobase + FSPI_FLSHA1CR0);
@@ -912,12 +912,19 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
nxp_fspi_clk_disable_unprep(f);
ret = clk_set_rate(f->clk, rate);
- if (ret)
- return;
+ if (ret) {
+ /*
+ * clk_set_rate() failed with the clocks already disabled.
+ * Re-enable them so the enable count matches what the caller's
+ * pm_runtime_put() (runtime_suspend) will drop.
+ */
+ nxp_fspi_clk_prep_enable(f);
+ return ret;
+ }
ret = nxp_fspi_clk_prep_enable(f);
if (ret)
- return;
+ return ret;
/*
* If clock rate > 100MHz, then switch from DLL override mode to
@@ -931,6 +938,8 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
f->pre_op_rate = op->max_freq;
f->selected = spi_get_chipselect(spi, 0);
+
+ return 0;
}
static int nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op)
@@ -1118,7 +1127,16 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
FSPI_STS0_ARB_IDLE, 1, POLL_TOUT, true);
WARN_ON(err);
- nxp_fspi_select_mem(f, mem->spi, op);
+ err = nxp_fspi_select_mem(f, mem->spi, op);
+ if (err) {
+ /*
+ * On failure the FlexSPI clock may be left disabled, so avoid
+ * any further register access (which would trigger a synchronous
+ * external abort) and bail out.
+ */
+ pm_runtime_put_autosuspend(f->dev);
+ return err;
+ }
nxp_fspi_prepare_lut(f, op);
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread