Repository navigation
Add centrally arbitrated DMA leases to dmdma - #2
Merged
Merged
Conversation
Lets peripheral drivers (dmuart, dmspi, dmsdio, ...) reserve and drive a DMA stream directly by calling dmdma as a DIF (Dmod_GetModuleContext + Dmod_GetDifFunction), instead of going through a /dev/dmdmaN/M device node - acquire/release, configure+start/abort, status, and callback registration. Both reservation paths (dmdrvi_open() and dmdma_lease_acquire()) share the same stream-slot bookkeeping, so a stream open as a device node can't also be leased and vice versa, and the same stream can never be acquired twice through any API combination. Also adds a real per-transfer watchdog: dmdma_transfer_config_t.timeout_ms arms a dmosi_timer that auto-aborts the stream and fires dmdma_event_timeout if it elapses, shared by both the lease and device-node ioctl paths. A new dmdma_event_aborted fires (synchronously, only if something was actually in flight) when a caller explicitly aborts. Transfer validation (direction vs. request-line consistency, address alignment, non-zero length) is now shared between both start paths via validate_transfer_config(). Verified on real STM32F746G-DISCO hardware (DMA2 stream 0): acquire, double- acquire rejection, a real mem-to-mem transfer with data verification and correct callback/user_ptr delivery, malformed-config rejection, abort while busy, the dmosi_timer watchdog firing dmdma_event_timeout, and clean release+re-acquire. Two real bugs only surfaced this way and are fixed here: dmod_dmdma_dif_api_declaration() never emits a runtime-visible registration when the implementing module is also the DIF-defining module (dmdma implementing its own "dmdma" DIF family) - worked around with an explicit registration macro - and the watchdog was being disarmed on every circular wrap instead of only on a genuinely terminal event, since dmdma_event_complete fires on every wrap for a circular transfer, not just at the end. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
dmdma is the one and only implementation of its lease functions - DIF is for a 1:N "multiple modules implement the same interface, discovered at runtime" relationship (e.g. dmramfs/dmffs both implementing dmfsi), which doesn't apply here. The previous DIF-based design needed a hand-written registration workaround because dmod_dmdma_dif_api_declaration() only registers when the implementing module differs from the DIF-defining one - a symptom of forcing the wrong tool onto a 1:1 relationship dmod's own "Module API" pattern already covers directly, with no such caveat. Consumers now just call dmdma_lease_acquire()/etc. directly - no Dmod_GetModuleContext()/Dmod_GetDifFunction() lookup - patched by the loader against dmdma's own registration exactly like dmdma_port_stream_*() already is. Whether a board needs DMA at all becomes a build-time choice (is dmdma bundled into that firmware image), not a per-call runtime check. Re-verified end to end on real STM32F746G-DISCO hardware after the switch; all dmdma_test_lease checks still pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
JohnAmadis
approved these changes
Sep 27, 2026
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.
Closes choco-technologies/dmod-ecosystem#10.
Summary
dmdma_lease.h:dmdma_lease_acquire/_release/_start/_abort/_is_busy/_get_remaining/_set_callback, exposed as a plain Module API (dmod's README, "Module API" section) - dmdma is the one and only implementation of it, so consumers just call these functions directly (e.g.dmdma_lease_acquire(controller, stream)), patched by the loader against dmdma's own registration exactly the waydmdma_port_stream_start()already works. No runtime lookup ceremony, noDmod_GetModuleContext()/Dmod_GetDifFunction()- that's DIF, which is for a 1:N "multiple modules implement the same interface, discovered at runtime" relationship (e.g. dmramfs/dmffs both implementing dmfsi), which doesn't apply here. (An earlier version of this branch used DIF for this and needed a hand-written registration workaround to make it work at all - that was the wrong tool for a 1:1 relationship; it's been replaced with the plain Module API pattern, which needs no such workaround.)/dev/dmdmaN/Mdevice-node opens share the exact same stream-slot bookkeeping (dmdma_slot_owner_ttag) - the same stream can never be acquired twice through any API combination, and a slot opened one way can't be driven through the other API.dmdma_transfer_config_t.timeout_ms: arms a realdmosi_timerwatchdog that auto-aborts the stream and fires a newdmdma_event_timeoutif the transfer doesn't finish in time - shared by both the lease and the existing device-node ioctl path.dmdma_event_aborted: fires (synchronously, only if a transfer was genuinely in flight) when a caller explicitly aborts, on both paths.validate_transfer_config()and shared by both start paths, instead of only partially checked in the ioctl path.Real-hardware verification (STM32F746G-DISCO, DMA2 stream 0)
Built a full
dmod-bootfirmware image against this branch and ran a new on-target smoke test (tests/dmdma_test_lease.c) through the actual shell console - not just host-side unit tests. All of the following passed on real silicon:user_ptrdmosi_timerwatchdog firesdmdma_event_timeoutand auto-stops the streamOne real bug only surfaced through this hardware run (fixed in this branch, not visible from compilation alone): the watchdog was being disarmed on every
dmdma_event_complete, but that flag fires at every wrap of a circular transfer, not just a true final completion - so a circular transfer's own watchdog was being cancelled after its first lap. Fixed by tracking whether the active transfer is circular and only treatingcompleteas terminal when it isn't.Test plan
stm32f4andstm32f7CPU families (arm-none-eabi-gcc)dmdma_test_dev/dmdma_test_porton-target smoke tests still compile against the updateddmdma_transfer_config_t(added explicittimeout_ms = 0)dmdma_test_leaseon-target smoke test passes end-to-end on real STM32F746G-DISCO hardware (see above), re-verified after switching from DIF to the plain Module API pattern