Page MenuHomeFreeBSD

linuxkpi: Fix DMA_BIDIRECTIONAL mapping
AcceptedPublic

Authored by zishun.yi.dev_gmail.com on Feb 25 2026, 5:28 AM.
Referenced Files
Unknown Object (File)
Wed, Aug 26, 7:31 PM
Unknown Object (File)
Fri, Aug 21, 3:58 AM
Unknown Object (File)
Sat, Aug 15, 8:33 AM
Unknown Object (File)
Thu, Aug 13, 1:21 AM
Unknown Object (File)
Wed, Aug 12, 12:56 PM
Unknown Object (File)
Wed, Aug 12, 12:56 PM
Unknown Object (File)
Wed, Aug 12, 12:37 PM
Unknown Object (File)
Wed, Aug 12, 12:25 AM

Details

Reviewers
bz
aokblast
Group Reviewers
linuxkpi
Summary

In dma_sync_single_for_cpu(), the DMA_BIDIRECTIONAL direction currently
performs BUS_DMASYNC_POSTREAD followed by BUS_DMASYNC_PREREAD. This
patch corrects the mapping to use BUS_DMASYNC_POSTREAD |
BUS_DMASYNC_POSTWRITE.

When ownership of the DMA area is transferred to the CPU, we must assume
the previous device access was bidirectional. Both POST operations are
necessary to ensure the CPU sees a consistent view of memory after
potential device reads and writes. A PREREAD is unnecessary here because
the device will no longer access the memory since ownership has been
transferred to the CPU.

Conversely, for dma_sync_single_for_device(), ownership is being
transferred back to the hardware. The buffer must be prepared for
potential bidirectional access by the device, requiring
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE.

PR: 293381
Reported by: Zishun Yi <zishun.yi.dev@gmail.com>
Fixes: 95edb10b47fc ("LinuxKPI: implement dma_sync_single_for_*, apply to (un)map single/sg")
Signed-off-by: Zishun Yi <zishun.yi.dev@gmail.com>

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 70977
Build 67860: arc lint + arc unit

Event Timeline

Isn't this closer to what I once had and hselasky said I should change?
Hah. I came back to this reivew to find the above question unsubmitted. I guess I left it for myself and lost the window.

Bumping this that I may have a look the next days hopefully.

In D55497#1320154, @bz wrote:

Isn't this closer to what I once had and hselasky said I should change?

IMO, hselasky said we cannot pass multiple flags to the non-bidirectional DMA cases. I think that is correct.
But I guess his thought was that some USB controllers might access the DMA buffer after the dma_sync_single_for_cpu, so he added the PREREAD flag. However, under Linux semantics, the device should not access the DMA buffer after the dma_sync_single_for_cpu.

I re-read the manual today:

BUS_DMASYNC_PREREAD    Perform any synchronization required prior
                       to an update of host memory by the device.

BUS_DMASYNC_PREWRITE   Perform any synchronization required after
                       an update of host memory by the CPU and
                       prior to device access to host memory.

BUS_DMASYNC_POSTREAD   Perform any synchronization required after
                       an update of host memory by the device and
                       prior to CPU access to host memory.

BUS_DMASYNC_POSTWRITE  Perform any synchronization required after
                       device access to host memory.

I think the code flow should be similar to:

preread -> device update memory -> postread-> cpu can read memory
cpu update memory -> prewrite -> device read memory -> postwrite

So, for dma_sync_single_for_cpu with DMA_BIDIRECTIONAL, it should use the two operations after device update memory and device read memory (i.e., POSTREAD and POSTWRITE).

Based on the code flow I mentioned above, I found that the DMA_TO_DEVICE and
DMA_FROM_DEVICE directions in dma_sync_single_for_device might be reversed.

This revision is now accepted and ready to land.Sat, Aug 22, 7:28 PM

@bz if you don't have any problem. I will merge this ptach next week.

I think the current version seems correct. Please go ahead, also take the PR, mark it for MFC15 at least (likely MFC14 as well) and close it once those are done. Please try to do the MFC15 timely. Thanks!