Skip to content

fix(sdcard): migrate dmaInit() to ownership-checked dmaAllocate() - #1398

Merged
nerdCopter merged 5 commits into
emuflight:masterfrom
nerdCopter:fix/dmainit-sdcard-migration
Aug 24, 2026
Merged

fix(sdcard): migrate dmaInit() to ownership-checked dmaAllocate()#1398
nerdCopter merged 5 commits into
emuflight:masterfrom
nerdCopter:fix/dmainit-sdcard-migration

Conversation

@nerdCopter

@nerdCopter nerdCopter commented Aug 18, 2026

Copy link
Copy Markdown
Member

AI Generated pull-request

Summary

Stage 5 of 5 in IT#1363's fleet-wide dmaInit()dmaAllocate() migration (stage 1 ADC, stage 2 transponder, stage 3 LED strip all merged; stage 4 motors/DSHOT MERGED). Converts sdcard.c (SPI-mode) and sdio_f4xx.c/sdio_f7xx.c (SDIO-mode) from unchecked dmaInit() to ownership-checked dmaAllocate() + dmaEnable().

Why this needed more than a mechanical swap

  • sdcard.c (SPI-mode): falls back to polled SPI (clearing useDMAForTx) on claim failure instead of aborting card init entirely. useDMAForTx is already checked as a runtime gate at every transfer/completion site in this file — this is a supported, pre-existing fallback path, not new code. Losing DMA acceleration is preferable to losing the SD card (and blackbox logging) over an unrelated DMA conflict.
  • sdio_f4xx.c/sdio_f7xx.c: SD_Initialize_LL() changed from void to bool, matching BF's actual return type, with the claim check moved to the very top of the function — before any RCC/GPIO/DMA register access. sdio_h7xx.c's no-op stub (H7 uses internal IDMA, no external stream) is now bool too, matching BF exactly.
  • Deliberately not matching BF 4.5-maintenance's exact identifier-resolution logic: BF's own SD_Initialize_LL() computes the DMA identifier from a file-scope static (dmaStream) that's only assigned after the ownership check — meaning dmaAllocate() always operates on an invalid/NULL-derived identifier and the function always returns false in 4.5-maintenance. This EF implementation resolves the identifier from the dma parameter instead, matching what BF's code clearly intended. That bug was independently confirmed fixed in current BF master (commit b551d654a, PR#14990, "Refactor DMA driver to abstract platform-specific types...", function renamed SD_InitialiseHardware) as a side effect of an unrelated, much larger DMA-API refactor — not a targeted fix. Per explicit instruction this is not filed upstream; tracked independently in ~/SYNC/nerdCopter-GIT/AI/EF/fix/dmainit-sdcard-migration/BF45-SDIO-DMASTREAM-BUG.md.
  • Caller-side NULL-deref fix: usbd_storage_sdio.c and sdcard_sdio_baremetal.c previously ignored SD_Initialize_LL()'s return value entirely. Since neither caller configures the DMA stream itself, a claim failure would leave the file-scope dma_stream pointer NULL, and the first real card transfer would dereference it in SD_StartBlockTransfert() — a hard fault, not a graceful failure. Both callers now check the return and bail to SDCARD_STATE_NOT_PRESENT (or an equivalent failure return) instead. Found via an opencode second-opinion pass, verified directly against source before fixing.
  • Double-init idempotency: sdcard_init()/SD_Initialize_LL() can each be called twice per boot — once from fc_init.c, once from the USB MSC passthrough path — for the same logical OWNER_SDCARD. Added sdcardDmaClaim()/sdioDmaClaim(), matching the existing uartDmaClaim()/dshotDmaClaim() pattern already in this codebase: a stream already held by the same owner+resourceIndex is treated as an already-successful claim, so the second call isn't mistaken for a real conflict.

Known architectural gap this PR does not close (tracked separately, not blocking)

sdcard.c (SPI-mode) still uses its own legacy per-driver DMA claim and the old raw-SPI polled API (spiInstanceByDevice(), spiTransfer()). BF 4.5-maintenance's equivalent (sdcard_spi.c) has no DMA-claim code of its own — it's fully migrated to the generic extDevice_t/spiSequence() bus-level mechanism (spiInitBusDMA() already claims DMA per-bus). This PR's dmaAllocate() fix is correct and safe for IT#1363's actual scope (ownership-check migration) but does not migrate sdcard.c onto that generic mechanism. Filed as #1399, sized comparable to the IMUF9001 legacy-DMA migration (#1143, closed) — a full driver rewrite, not part of this PR. SDIO mode (sdio_f4xx.c/sdio_f7xx.c) has no equivalent gap — BF's own SDIO driver also claims DMA per-driver (SDIO isn't part of the generic SPI-bus abstraction).

BF-master verdict check

Per the corrected /bf-gaps process (4.5-maintenance is the reference, master checked as fallback for bugfixes/architecture direction, not the primary diff target): git log 4.5-maintenance..master confirms the SD_Initialize_LL() identifier bug above as 4.5-only (fixed in master's b551d654a). A second verdict for the sdcard.c architectural gap (#1399): not-comparable — EF has no BF-equivalent file to diff against, since BF's sdcard_spi.c never had per-driver DMA-claim code to begin with. Full inventory: fix/dmainit-sdcard-migration/dmainit-sdcard-migration-bf-gaps.md; both verdicts logged in MIGRATION.md § BF-branch register.

Review history

Local coderabbit review --agent: 0 findings, both rounds. An opencode second-opinion pass on the first round found two real issues (the NULL-deref and double-init cases above), both fixed and re-verified; a follow-up opencode pass on the fixed diff could not complete (infra instability, multiple models failing) and was not retried further, matching prior-session precedent for this tool. GitHub CodeRabbit's formal review: APPROVED, no actionable comments, all 7 changed files LGTM. A targeted analysis request (idempotent-reclaim logic + BF-bug avoidance) came back clean: confirmed both SPI-mode and SDIO-mode reclaim logic handle either boot-order permutation correctly, and confirmed no equivalent stale-static-before-assignment bug exists elsewhere in either file.

Verification

  • Build: 7/7 targets, no warnings — HELIOSPRING/FOXEERF722V4/STELLARH7DEV (3 real aircraft, all compile-gate only since none define USE_SDCARD), plus MLTYPHF4 (F4, SPI-mode + DMA), FLYSPARKF4 (F4, SDIO-mode), SPEEDYBEEF7V3 (F7, SDIO-mode), plus SITL.
  • Host unit tests: make test — 48/48 test binaries pass (up from 43; added sdcard_dma_claim_unittest.cc, host coverage for sdcardDmaClaim()/sdioDmaClaim() — see PR comment for scope/rationale).
  • No real-hardware verification of a normally-configured target is possible — none of the 3 real aircraft compile USE_SDCARD, and no USE_SDCARD-capable board (flight or bench) exists in inventory at all.
  • The ownership-check conflict mechanism itself was bench-verified on real silicon, both MCU families (2026-08-24, not part of this PR's diff — local-only, uncommitted target.h/target.mk edits on two owned bench boards, SKYSTARSF405AIO/F4-STDPERIPH and TMOTORF7/F7-HAL, neither a real-aircraft target). USE_SDCARD was temporarily enabled sharing an existing SPI bus with a spare, verified-free CS pin, with the SD card's DMA stream deliberately pointed at the same stream the board's own ADC already owns (DMA2_Stream3/DMA2_Stream4 respectively) — a real, physical ownership conflict, not simulated. On both boards, with sdcard_dma confirmed ON (get sdcard_dma), dma CLI output showed the ADC's stream unchanged after reboot: sdcardDmaClaim()'s ownership check correctly rejected the conflicting claim and fell back to polled SPI, no crash, no stolen stream. This does not test a real card's read/write path (none was present, none is needed to exercise the claim/conflict logic) and does not change the risk framing below for a normally-configured target — it confirms the specific new mechanism this PR adds actually works on hardware, across both MCU families.
  • Compile-gate + bench-target build otherwise. Accepted as a documented, known risk for the remaining untested surface: this is a blackbox-logging peripheral, not a flight-control one — worst-case failure (SD card not detected, or SPI-mode fallback to polled transfer) is a logging/data-loss risk, not a flight-safety risk, unlike PR#1397 (motors). Marked DRAFT pending full hardware acquisition, not pending further code changes.

Related

Summary by CodeRabbit

  • Bug Fixes
    • Improved SD card initialization reliability when DMA resources are unavailable or already in use.
    • Automatically falls back to polled transfers when DMA cannot be claimed.
    • SD card and USB storage initialization now stop cleanly when low-level setup fails.
    • Prevented invalid or conflicting DMA configurations from being used.
    • Improved handling when the same SD card transfer resource is initialized more than once.

sdcard.c (SPI-mode) and sdio_f4xx.c/sdio_f7xx.c (SDIO-mode) called
dmaInit(), which silently overwrites any existing DMA owner. Replace
with dmaAllocate() + dmaEnable(), matching the pattern already used
by ADC, transponder, LED strip, and motors.

sdcard.c falls back to polled SPI (clearing useDMAForTx) on claim
failure instead of aborting card init entirely -- useDMAForTx is
already checked as a runtime gate at every transfer/completion site,
so this is a supported fallback, not a new code path. Losing DMA
acceleration is preferable to losing the SD card (and blackbox
logging) over an unrelated DMA conflict.

sdio_f4xx.c/sdio_f7xx.c change SD_Initialize_LL() from void to bool,
matching BF's return type, with the claim check moved to the very
top before any RCC/GPIO/DMA register access. sdio_h7xx.c's no-op
stub (H7 uses internal IDMA) is now bool too, matching BF exactly.

The claim intentionally resolves the DMA identifier from the `dma`
parameter, not a file-scope static -- BF 4.5-maintenance's own
equivalent computes it from a stale static assigned only after the
check, making dmaAllocate() operate on an invalid identifier and the
function always return false. That bug was fixed in BF master
(PR#14990, function since renamed SD_InitialiseHardware) as a side
effect of an unrelated DMA-API refactor, not a targeted fix. Not
filed upstream per explicit instruction; tracked in
BF45-SDIO-DMASTREAM-BUG.md instead.

Two callers (usbd_storage_sdio.c, sdcard_sdio_baremetal.c) previously
ignored SD_Initialize_LL()'s return value entirely. Since neither
caller configures the DMA stream itself, a claim failure would leave
the file-scope dma_stream pointer NULL, and the first real card
transfer would dereference it in SD_StartBlockTransfert() -- both
callers now check the return and bail to SDCARD_STATE_NOT_PRESENT
(or an equivalent failure return) instead.

sdcard_init() and SD_Initialize_LL() can each be called twice per
boot (once from fc_init.c, once from the USB MSC passthrough path)
for the same logical OWNER_SDCARD. Added sdcardDmaClaim()/
sdioDmaClaim(), matching the existing uartDmaClaim()/dshotDmaClaim()
pattern: a stream already held by the same owner+resourceIndex is
treated as an already-successful claim, so the second call is not
mistaken for a real conflict.
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c13d607b-034a-4773-a772-9395ba5e2e17

📥 Commits

Reviewing files that changed from the base of the PR and between a539314 and 678da01.

📒 Files selected for processing (9)
  • src/main/drivers/sdcard.c
  • src/main/drivers/sdcard_sdio_baremetal.c
  • src/main/drivers/sdio_f4xx.c
  • src/main/drivers/sdio_f7xx.c
  • src/main/drivers/sdio_h7xx.c
  • src/main/drivers/sdmmc_sdio.h
  • src/main/msc/usbd_storage_sdio.c
  • src/test/Makefile
  • src/test/unit/sdcard_dma_claim_unittest.cc

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.

📜 Recent review details
⏰ Context from checks skipped due to timeout. (13)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: build (targets-group-10)
  • GitHub Check: build (targets-group-9)
  • GitHub Check: build (targets-group-5)
  • GitHub Check: build (targets-group-2)
  • GitHub Check: build (targets-group-11)
  • GitHub Check: build (targets-group-3)
  • GitHub Check: build (targets-group-7)
  • GitHub Check: build (targets-group-6)
  • GitHub Check: build (targets-group-rest)
  • GitHub Check: build (targets-group-8)
  • GitHub Check: build (targets-group-4)
  • GitHub Check: build (targets-group-1)
🔇 Additional comments (7)
src/main/drivers/sdmmc_sdio.h (1)

219-219: LGTM!

src/main/drivers/sdio_f4xx.c (1)

1308-1325: LGTM!

Also applies to: 1378-1378, 1390-1392

src/main/drivers/sdio_f7xx.c (1)

1329-1346: LGTM!

Also applies to: 1402-1402, 1414-1416

src/main/drivers/sdio_h7xx.c (1)

737-740: LGTM!

src/main/drivers/sdcard.c (1)

476-484: LGTM!

Also applies to: 501-511

src/main/drivers/sdcard_sdio_baremetal.c (1)

289-296: LGTM!

src/main/msc/usbd_storage_sdio.c (1)

155-155: LGTM!


📝 Walkthrough

Walkthrough

SD-card and SDIO initialization now claim DMA resources with owner-aware reuse. F4 and F7 drivers return initialization status. SD-card and USB storage callers handle DMA or low-level initialization failures. Unit tests cover claim reuse and conflicts.

Changes

SD DMA initialization

Layer / File(s) Summary
SDIO DMA ownership and return status
src/main/drivers/sdmmc_sdio.h, src/main/drivers/sdio_f4xx.c, src/main/drivers/sdio_f7xx.c, src/main/drivers/sdio_h7xx.c
SD_Initialize_LL now returns bool. F4 and F7 implementations validate, claim, enable, and configure supported DMA streams.
SPI SD-card DMA fallback
src/main/drivers/sdcard.c
SD-card initialization reuses matching DMA claims and falls back to polled SPI when another owner holds the resource.
Initialization failure propagation
src/main/drivers/sdcard_sdio_baremetal.c, src/main/msc/usbd_storage_sdio.c
Callers now handle failed low-level SD initialization and update failure state or return failure.
DMA claim validation tests
src/test/Makefile, src/test/unit/sdcard_dma_claim_unittest.cc
Tests cover initial allocation, same-owner reuse, foreign-owner conflicts, and resource-index mismatches for SPI and SDIO claims.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to 678da

This localized DMA ownership change includes a polled-transfer fallback and updated failure handling, with reported build and unit-test coverage. No actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant STORAGE_Init
  participant SD_Initialize_LL
  participant DMA
  STORAGE_Init->>SD_Initialize_LL: initialize SDIO DMA
  SD_Initialize_LL->>DMA: claim and enable DMA stream
  alt initialization succeeds
    SD_Initialize_LL-->>STORAGE_Init: return true
  else initialization fails
    SD_Initialize_LL-->>STORAGE_Init: return false
    STORAGE_Init-->>STORAGE_Init: return failure
  end
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring check was indeterminate for this PR — some files could not be analyzed in time. Not blocking.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the SD-card DMA migration from dmaInit() to ownership-checked dmaAllocate().
Description check ✅ Passed The description thoroughly covers the change, rationale, scope, risks, related issues, review history, and verification results.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nerdCopter

Copy link
Copy Markdown
Member Author

@coderabbitai, AI generated comment

Requesting analysis, not a full review.

sdcard.c (SPI-mode) and sdio_f4xx.c/sdio_f7xx.c (SDIO-mode) migrate dmaInit() to dmaAllocate() + dmaEnable(). Two things specific to this PR worth independent verification:

  1. sdcard_init() and SD_Initialize_LL() can each be called twice per boot on a USE_USB_MSC target -- once from fc_init.c, once from the USB MSC passthrough path (usbd_storage_sd_spi.c / usbd_storage_sdio.c) -- for the same logical OWNER_SDCARD. sdcardDmaClaim()/sdioDmaClaim() (new, static, matching the existing uartDmaClaim() pattern in serial_uart_stm32f4xx.c) treat a stream already owned by the same owner+resourceIndex as an already-successful claim. Please verify this correctly covers both call orders (fc_init.c first, or the USB MSC path first) without a false-negative conflict.

  2. SD_Initialize_LL() in sdio_f4xx.c/sdio_f7xx.c deliberately resolves its DMA identifier from the dma function parameter, not the file-scope dma_stream static -- this differs from BF 4.5-maintenance's own SD_Initialize_LL(), which computes the identifier from that static before it's ever assigned (a real bug, confirmed fixed in current BF master as SD_InitialiseHardware(), commit b551d654a). Please confirm EF's version has no equivalent ordering issue anywhere else in these two files -- any other read of a DMA-related static before its own assignment.

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Locate candidate files ==='
fd -t f -a '^(sdcard|sdio_f4xx|sdio_f7xx|fc_init|usbd_storage_sd_spi|usbd_storage_sdio|serial_uart_stm32f4xx)\.(c|h)$' . || true

echo '=== Function maps ==='
for f in $(fd -t f -a '^(sdcard|sdio_f4xx|sdio_f7xx|fc_init|usbd_storage_sd_spi|usbd_storage_sdio|serial_uart_stm32f4xx)\.c$' .); do
  echo "--- $f"
  ast-grep outline "$f" --items all --type function 2>/dev/null || true
done

echo '=== Relevant declarations, assignments, claims, and call sites ==='
rg -n -C 5 -P '\b(sdcardDmaClaim|sdioDmaClaim|uartDmaClaim|sdcard_init|SD_Initialize_LL|dmaAllocate|dmaEnable|dmaGetIdentifier|dma_stream|dmaStream|useDMAForTx)\b' \
  -g 'sdcard.c' -g 'sdio_f4xx.c' -g 'sdio_f7xx.c' -g 'fc_init.c' \
  -g 'usbd_storage_sd_spi.c' -g 'usbd_storage_sdio.c' -g 'serial_uart_stm32f4xx.c' .

echo '=== DMA-related static declarations and writes in SDIO implementations ==='
rg -n -C 4 -P '^\s*static\b.*\bdma|^\s*(dma_stream|dmaStream|dma)\s*=|\bdma_stream\b|\bdmaStream\b|\bdmaGetIdentifier\s*\(' \
  -g 'sdio_f4xx.c' -g 'sdio_f7xx.c' .

Length of output: 61568


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== SPI initialization and USB-MSC path ==='
sed -n '488,545p' src/main/drivers/sdcard.c
sed -n '570,610p' src/main/fc/fc_init.c
sed -n '130,165p' src/main/msc/usbd_storage_sd_spi.c

echo '=== All SDIO low-level initialization call sites and declarations ==='
rg -n -C 8 -P '\bSD_Initialize_LL\s*\(' -g '*.[ch]' .

echo '=== SDIO-mode initialization dispatch and USB-MSC path ==='
rg -n -C 10 -P '\b(SDIO_DMA|SD_Initialize_LL|SD_Init|sdcard_init)\b' \
  -g 'sdcard.c' -g 'fc_init.c' -g 'usbd_storage_sdio.c' -g '*sdio*.[ch]' .

echo '=== Every dma_stream occurrence, with function boundaries ==='
for f in src/main/drivers/sdio_f4xx.c src/main/drivers/sdio_f7xx.c; do
  echo "--- $f"
  rg -n -C 12 -P '\bdma_stream\b' "$f"
done

echo '=== DMA-related file-scope state and direct DMA API calls in SDIO implementations ==='
for f in src/main/drivers/sdio_f4xx.c src/main/drivers/sdio_f7xx.c; do
  echo "--- $f"
  rg -n -C 5 -P '^\s*(static\s+)?(?:DMA_\w+|DMA_Stream_TypeDef|dma\w*)[^;]*;|\b(dmaAllocate|dmaEnable|dmaGetIdentifier|dmaGetDescriptorByIdentifier|dmaSetHandler|dmaGetOwner|dmaGetResourceIndex)\s*\(' "$f"
done

Length of output: 73785


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== SD-card configuration declaration, registration, and mutation sites ==='
rg -n -C 6 -P '\b(dmaIdentifier|sdcardConfig|sdcardConfigMutable|PG_SDCARD_CONFIG|pgResetFn_sdcardConfig)\b' \
  -g '*.[ch]' .

echo '=== SDIO_DMA definitions and board-level overrides ==='
rg -n -C 5 -P '^\s*#\s*define\s+SDIO_DMA\b|\bSDIO_DMA\b' \
  -g '*.[ch]' .

echo '=== DMA identifier-to-reference mapping API and validation ==='
rg -n -C 6 -P '\b(dmaGetRefByIdentifier|dmaGetIdentifier|dmaAllocate|dmaGetOwner|dmaGetResourceIndex)\s*\(' \
  -g '*.[ch]' src/main

Length of output: 69896


@nerdCopter, I found no issue in the requested scope.

  1. The re-claim logic covers both call orders.
  • In SPI mode, fc_init.c and usbd_storage_sd_spi.c both call sdcard_init(sdcardConfig()).

  • Both calls use the same config->dmaIdentifier, OWNER_SDCARD, and resource index 0.

  • sdcardDmaClaim() returns true when that stream already has OWNER_SDCARD and index 0.

  • Therefore, either caller can claim first. The second caller does not call dmaAllocate() and does not get a false conflict.

  • In SDIO mode, the boot path in sdcard_sdio_baremetal.c passes the stream resolved from sdcardConfig()->dmaIdentifier.

  • The USB-MSC path in usbd_storage_sdio.c passes SDIO_DMA.

  • src/main/pg/sdcard.c initializes dmaIdentifier from dmaGetIdentifier(SDIO_DMA).

  • dmaIdentifier is not exposed as a user setting. The exposed SD-card DMA setting only controls useDma.

  • Therefore, both paths resolve to the target-defined SDIO_DMA stream.

  • sdioDmaClaim() in both sdio_f4xx.c and sdio_f7xx.c uses the same owner and index check. Either call order succeeds.

  1. The F4 and F7 SDIO implementations have no equivalent ordering defect.
  • SD_Initialize_LL() first validates the dma parameter against DMA2_Stream3 and DMA2_Stream6.
  • It then calls sdioDmaClaim(dmaGetIdentifier(dma), OWNER_SDCARD, 0) and dmaEnable(dmaGetIdentifier(dma)).
  • These operations do not read dma_stream.
  • Each implementation assigns dma_stream = dma before its first later use in the initialization function.
  • The remaining dma_stream reads occur in SD_StartBlockTransfert() and the SDIO/SDMMC interrupt handler. Those paths require successful low-level initialization before a transfer can start.
  • I found no other DMA-related file-scope static that is read to derive an identifier before its assignment.

You are interacting with an AI system.

@nerdCopter
nerdCopter marked this pull request as ready for review August 18, 2026 18:35
@nerdCopter
nerdCopter marked this pull request as draft August 18, 2026 18:47
sdcardDmaClaim()/sdioDmaClaim() had zero host coverage. Mirrors the same
fake-DMA-state convention already used by serial_uart_dma_claim_unittest.cc
for uartDmaClaim() -- compiling the real sdcard.c/sdio_f4xx.c/sdio_f7xx.c
under UNIT_TEST needs a disproportionate register-mock surface (90+
SDIO->/RCC-> field accesses in sdio_f4xx.c alone) for logic these two
functions don't touch, same class of tradeoff already made for
bus_spi_ll.c/bus_spi_stdperiph.c in feat/dma-ll-unittest-infra.

Covers: fresh claim on a free stream, same-owner/index reopen (the
fc_init.c-vs-USB-MSC-passthrough dual-caller scenario), foreign-owner
conflict, same-owner-different-index conflict.
@nerdCopter

Copy link
Copy Markdown
Member Author

AI Generated comment

Added host unit-test coverage for sdcardDmaClaim()/sdioDmaClaim() (commit 678da01): fresh claim on a free stream, same-owner/index reopen (the fc_init.c-vs-USB-MSC-passthrough dual-caller scenario), foreign-owner conflict, same-owner-different-resource-index conflict.

Testing approach: mirrors the claim logic with fake DMA state rather than compiling the real sdcard.c/sdio_f4xx.c/sdio_f7xx.c under UNIT_TEST. Investigated compiling the real files directly (matching how dma_stm32f4xx_unittest.cc compiles the real DMA layer) and found it disproportionate: sdio_f4xx.c alone has 90+ direct SDIO->/RCC-> register accesses unrelated to the claim helper, the same class of blocker already documented for bus_spi_ll.c/bus_spi_stdperiph.c in the DMA/LL unit-test infra work. This matches the existing convention already used for the identical reclaim-guard shape elsewhere in this codebase (uartDmaClaim() in serial_uart_dma_claim_unittest.cc, merged and hardware-verified separately) — the claim logic itself is duplicated per-file 8 times fleet-wide (uartDmaClaim x3, dshotDmaClaim x2, sdioDmaClaim x2, sdcardDmaClaim x1), and none of the other 7 sites get real-file-compiled test coverage either.

make clean_test && make test: 48/48 binaries pass, 0 failures, 0 new warnings.

Second-opinion review on the current diff (post-fix, both files touched by this PR): opencode ran clean, 0 new findings, explicitly re-confirmed the two previously-fixed issues (unchecked SD_Initialize_LL() return, double-init idempotency) stay fixed. A second independent tool (pi/OpenRouter) could not run this round — every free-tier model on this account returned "unavailable for free," a provider-side gap, not a code finding.

No SD-card-capable hardware exists in inventory to verify this on target — confirmed again this session that EmuFlight's own SITL target does not compile sdcard.c/sdio_*.c at all (grepped SITL/, zero references), so there is no software-only way to exercise the real register-level DMA/SDIO code path without physical hardware. This PR's risk profile (blackbox-logging peripheral, not flight-critical) and the compile-gate + host-test + multi-round review already performed remain the practical ceiling until SD-capable hardware is available.

@nerdCopter

Copy link
Copy Markdown
Member Author

AI Generated comment

@coderabbitai full review

New commit (678da01) adds host unit-test coverage for sdcardDmaClaim()/sdioDmaClaim() (src/test/unit/sdcard_dma_claim_unittest.cc, src/test/Makefile) since the prior APPROVED review predates it.

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

@nerdCopter: I will perform a full review of the current PR, including commit 678da0156 and its unit-test coverage.

✅ Action performed

Full review finished.

@nerdCopter
nerdCopter marked this pull request as ready for review August 24, 2026 18:04
@nerdCopter
nerdCopter merged commit 332779b into emuflight:master Aug 24, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant