[PATCH AUTOSEL 6.18-6.1] spi: dw: fix wrong RX_SAMPLE_DLY setting after resume

From: Sasha Levin

Date: Mon Aug 31 2026 - 11:45:43 EST


From: Jisheng Zhang <jszhang@xxxxxxxxxx>

[ 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@xxxxxxxxxx>
Suggested-by: Mark Brown <broonie@xxxxxxxxxx>
Link: https://patch.msgid.link/20260803135925.12622-1-jszhang@xxxxxxxxxx
Signed-off-by: Mark Brown <broonie@xxxxxxxxxx>
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---

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@xxxxxxxxxx>` (author)
- **Suggested-by:** Mark Brown `<broonie@xxxxxxxxxx>` (SPI subsystem
maintainer)
- **Link:**
https://patch.msgid.link/20260803135925.12622-1-jszhang@xxxxxxxxxx
- **Signed-off-by:** Mark Brown `<broonie@xxxxxxxxxx>` (maintainer ack)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Cc:
stable@xxxxxxxxxxxxxxx`
- 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@xxxxxxxxxx. `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