SDHCI: fix silent read failures and unbootable warm reset with UHS-I cards - #853
Open
dgarske wants to merge 1 commit into
Open
SDHCI: fix silent read failures and unbootable warm reset with UHS-I cards#853dgarske wants to merge 1 commit into
dgarske wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes SDHCI-related silent read failures that could surface later as integrity failures, and adds a warm-reset recovery path for SD cards left in UHS-I 1.8V signaling by a prior stage. This improves boot reliability on affected targets (e.g., ZCU102) and adds regression coverage for the SDMA timeout case.
Changes:
- Preserve earlier transfer failures in
sdhci_transfer()so CMD12 / busy-wait results can’t overwrite timeouts and falsely report success. - Treat short reads during disk image load as an I/O error (with byte counts) instead of letting truncated images reach integrity checks.
- Add an SD-card warm-reset recovery retry that switches host signaling to 1.8V after an actual data failure, plus a new unit test for SDMA timeout reporting.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/unit-tests/unit-sdhci-dma-error.c | New regression test ensuring SDMA timeout is reported as error (and positive control for success path). |
| tools/unit-tests/Makefile | Adds the new unit test binary to the unit test build/run list. |
| src/update_disk.c | Flags ret == 0 / short reads as errors and reports byte counts to avoid misleading integrity failures. |
| src/sdhci.c | Preserves SDMA timeout errors across CMD12, and adds UHS-I warm-reset recovery retry after failed reads. |
| include/sdhci.h | Adds SDHCI_SRS15_V18SE bit definition for Host Control 2’s 1.8V signaling enable. |
| .gitignore | Ignores the newly built unit test binary. |
Suppressed comments (3)
src/sdhci.c:376
sdhci_uhs_recover()is specific to SD UHS-I warm-reset recovery. If it is compiled for eMMC-only configurations it will be unused (triggering-Werror) and, if accidentally called, would apply an SD-specific recovery sequence and log message. Wrap the helper in#ifdef DISK_SDCARDto keep it out of eMMC-only builds.
/* Recover a card that a previous stage left in UHS-I 1.8V signaling.
*
* A card that negotiated UHS-I only returns to 3.3V when VDD is removed --
src/sdhci.c:1843
- The UHS-I warm-reset recovery retry should only be compiled/enabled for SD-card builds. Without a
DISK_SDCARDguard, eMMC-only builds will fail to compile oncesdhci_uhs_recover()is SD-only, and even today the retry path is semantically wrong for eMMC.
if (status != 0 && sdhci_uhs_recover() == 0) {
continue; /* retry this chunk with matched signaling */
}
src/sdhci.c:418
- Close the
#ifdef DISK_SDCARDguard forsdhci_uhs_recover()so the rest of the file is not unintentionally made SD-only.
}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
78
to
+80
| static uint32_t g_rca = 0; /* SD Card Relative Address */ | ||
| /* Set once sdhci_uhs_recover() has switched the host to 1.8V signaling. */ | ||
| static int g_uhs_recovered = 0; |
Comment on lines
+52
to
+55
| uint64_t hal_get_timer_us(void) | ||
| { | ||
| return 0; | ||
| } |
dgarske
force-pushed
the
zynqmp_sdhci_reset
branch
from
August 11, 2026 21:35
6e7d46b to
fd18573
Compare
dgarske
force-pushed
the
zynqmp_sdhci_reset
branch
from
August 11, 2026 22:40
fd18573 to
38ec1e1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found on a ZCU102 SD-boot target. Two related problems.
1. A failed SDMA transfer was reported as success
sdhci_transfer()setsstatus = -1when the Transfer Complete wait times out, but the post-transfer error check then ran unconditionally and CMD12's result overwrote it. A wolfBoot-side wait timeout does not necessarily set anSRS12error bit, so the function returned 0 after moving no data. The caller used a partially filled buffer, which surfaced later as an image integrity failure rather than the I/O error it was -- and with anti-rollback, the good lower-versioned slot was refused too, leaving nothing bootable.CMD12 is still issued on failure to leave the bus sane, but no longer clears the error.
update_disk.calso broke its load loop onret <= 0while only erroring onret < 0, and never checked the loop reachedfw_size; short reads are now reported as I/O with byte counts.2. A card left in UHS-I is unusable until power is removed
An OS that negotiates UHS-I leaves the card at 1.8V. Per the SD spec a card only returns to 3.3V when VDD is removed -- CMD0 does not do it -- and on many boards the card supply is a fixed rail software cannot switch. After a warm reset the card is still at 1.8V while the bootloader comes up at 3.3V. The command path tolerates that, so init and isolated reads work; sustained transfers do not.
It cannot be detected up front: the warm reset clears the controller registers, so the inherited
V18SEbit is gone before the bootloader runs (an early-sample implementation was tried on hardware and never triggered), and the corruption is marginal enough that a short probe read usually succeeds. So recovery is driven from an actual data failure -- switch the host to meet the card and retry, at most once per boot. A cold boot never reaches it. This restores signaling the card is already using, so no CMD11 voltage switch is involved.Evidence
0xFF1700000x3CHost Control 20x008B= V18SE + SDR1040x0001= SDR25, V18SE clear0x2CClock Control0x0007undivided0x0207divider 2Building with
SDHCI_FORCE_SINGLE_BLOCK_READremoves both SDMA and CMD18, leaving plain CMD17 PIO. It still failed, witherror SRS12: 0x00208041-- Data CRC Error. Command completes, card sends data, data arrives corrupt: not a DMA bug, not a multi-block bug.Ruled out by measurement: SMMU blocking DMA (
SCR0=0x00200001, in bypass); a missing controller reset (HRS00_SWRmaps to a realSRAwrite, readback polls the real bit); software power-cycling the card (10 ms with bus power dropped changed nothing -- VDD is not switchable here).Testing
New regression test drives a multi-block SDMA read whose Transfer Complete never arrives, with a clean
SRS12and a succeeding CMD12. Verified to fail without the fix (returned 0) and pass with it; a positive control confirms the mock can succeed.Hardware, ZCU102 (
zynqmp_sdcard_ramdisk.config, RSA4096/SHA3), cross-built and flashed to QSPI:The recovery costs one failed transfer before engaging. The cleanest long-term fix is for the OS to return the card to 3.3V/idle on shutdown; this makes the bootloader survive an OS that does not.