Page MenuHomeFreeBSD

ti_sdhci: offload the MMC data phase to EDMA3
Needs ReviewPublic

Authored by rick_sloservers.com on Sun, Aug 23, 1:40 PM.

Details

Reviewers
manu
imp
andrew
oh
Summary

microSD reads on am335x cost about 90% of the single core, almost all of it in interrupt context, because ti_sdhci is PIO only:

19.47 MB/s   busy 93.8%   (sys 3.7% intr 89.6% idle 6.2%)

SD_CAPA advertises SDMA, but the MMCHS OCP master interface is not implemented on this SoC: SD_CON[20] DMA_MnS is documented as "not available on this device" (AM335x TRM SPRUH73Q 18.5.1.5). The controller can only ever be a DMA slave, and sdhci(4) implements SDMA, which is bus mastering by definition. Clearing SDHCI_QUIRK_BROKEN_DMA makes the first data transfer time out and loses the storage path entirely.

Use the platform hooks sdhci(4) already provides platform_will_handle, platform_start_transfer, platform_finish_transfer with EDMA3 driving the controller's SDTXEVT/SDRXEVT slave request lines. bcm2835_sdhci(4) is the existing precedent for the same shape: a controller that cannot master, paired with a separate SoC DMA engine.

Note the quirk deliberately stays set. It only clears SDHCI_HAVE_DMA, which governs sdhci(4) programming a system address and letting the controller master the bus. The offload attaches on a different path: sdhci(4) reaches the platform hooks from its PIO handler, so EDMA3 replaces the byte copy rather than SDHCI DMA. The controller never masters anything, and the data phase never touches the CPU.

Two hardware details shape the implementation. SD_CMD[0] DE must be set by the same register write that issues the command (18.3.5.1); ti_sdhci already defers the transfer mode and writes command and mode together, so that write is the arming point. And with DE set the controller reports only command complete and transfer complete — one interrupt per transfer rather than per block.

The caller's buffer is mapped and each physically contiguous run described by its own PaRAM set, linked into a chain the channel controller walks unaided, so there is no copy. PaRAM sets 0-63 belong to the channels, so chains are built from spare sets above those. Transfers that cannot be mapped in place fall back to a bounce buffer; that is 12.5% of data phases, all of them buffers starting on a cache line but not a block boundary, so a block straddles two segments and one request moves exactly one block.

Reading 150MB from microSD at 1000MHz, three trials each:

PIO             19.2-19.6 MB/s  busy 92.6%  intr 89.2%  idle  7.4%
EDMA3, mapped   18.9-19.0 MB/s  busy  6.0%  intr  2.2%  idle 94.0%

Just under 98% of the throughput the CPU achieves by hand, for a fifteenth of the CPU time and a fortieth of the time in interrupt context.

Derived from the AM335x TRM (SPRUH73Q) and from BSD licensed FreeBSD source: sdhci.c, sdhci_if.m, bcm2835_sdhci.c and the pre-existing ti_edma3.c. No GPL licensed source was consulted.

Depends on D59124.

Test Plan

Reads compare equal to PIO over repeated 32MB and 150MB passes on both microSD and eMMC. A pattern written by EDMA3 into unpartitioned space at the end of the eMMC reads back identical through PIO, which checks the write path independently of the read path.

Six reboot cycles with the offload enabled reached multi-user with no attach failures and no controller errors, and the root filesystem is mounted through it. 15.1-STABLE measures the same as 14.5-STABLE.

Nothing in-tree builds this file today, so compile coverage requires an AM335x kernel config — see D46703.

Full evidence and the measurement method: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=297800

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

rick_sloservers.com created this revision.