The branch main has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=6e1436d748273be52fb155914db3efae075a8619
commit 6e1436d748273be52fb155914db3efae075a8619 Author: Zishun Yi <[email protected]> AuthorDate: 2026-09-04 19:11:35 +0000 Commit: Bjoern A. Zeeb <[email protected]> CommitDate: 2026-09-04 22:52:24 +0000 LinuxKPI: Fix DMA_BIDIRECTIONAL and other mappings 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, 297155 Reported by: Zishun Yi <[email protected]> Reported by: Kim Shrier (fbsdbugs westryn.net) Fixes: 95edb10b47fc ("LinuxKPI: implement dma_sync_single_for_*, apply to (un)map single/sg") Signed-off-by: Zishun Yi <[email protected]> Reviewed by: aokblast, bz Differential Revision: https://reviews.freebsd.org/D55497 --- sys/compat/linuxkpi/common/include/linux/dma-mapping.h | 10 ++++------ sys/compat/linuxkpi/common/src/linux_pci.c | 15 ++++++++------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h index d29006cb52d3..ce0703bd7999 100644 --- a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h +++ b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h @@ -262,9 +262,7 @@ dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma, size_t size, switch (direction) { case DMA_BIDIRECTIONAL: - op = BUS_DMASYNC_POSTREAD; - linuxkpi_dma_sync(dev, dma, size, op); - op = BUS_DMASYNC_PREREAD; + op = BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE; break; case DMA_TO_DEVICE: op = BUS_DMASYNC_POSTWRITE; @@ -294,13 +292,13 @@ dma_sync_single_for_device(struct device *dev, dma_addr_t dma, switch (direction) { case DMA_BIDIRECTIONAL: - op = BUS_DMASYNC_PREWRITE; + op = BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD; break; case DMA_TO_DEVICE: - op = BUS_DMASYNC_PREREAD; + op = BUS_DMASYNC_PREWRITE; break; case DMA_FROM_DEVICE: - op = BUS_DMASYNC_PREWRITE; + op = BUS_DMASYNC_PREREAD; break; default: return; diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c index a49254425b5d..9e11f53cb299 100644 --- a/sys/compat/linuxkpi/common/src/linux_pci.c +++ b/sys/compat/linuxkpi/common/src/linux_pci.c @@ -1842,8 +1842,8 @@ lkpi_dma_unmap(struct device *dev, dma_addr_t dma_addr, size_t len, /* dma_sync_single_for_cpu() unrolled to avoid lock recursicn. */ switch (direction) { case DMA_BIDIRECTIONAL: - bus_dmamap_sync(obj->dmat, obj->dmamap, BUS_DMASYNC_POSTREAD); - bus_dmamap_sync(obj->dmat, obj->dmamap, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(obj->dmat, obj->dmamap, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); break; case DMA_TO_DEVICE: bus_dmamap_sync(obj->dmat, obj->dmamap, BUS_DMASYNC_POSTWRITE); @@ -2053,13 +2053,14 @@ linux_dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl, int nents, switch (direction) { case DMA_BIDIRECTIONAL: - bus_dmamap_sync(priv->dmat, sgl->dma_map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(priv->dmat, sgl->dma_map, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); break; case DMA_TO_DEVICE: - bus_dmamap_sync(priv->dmat, sgl->dma_map, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(priv->dmat, sgl->dma_map, BUS_DMASYNC_PREWRITE); break; case DMA_FROM_DEVICE: - bus_dmamap_sync(priv->dmat, sgl->dma_map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(priv->dmat, sgl->dma_map, BUS_DMASYNC_PREREAD); break; default: break; @@ -2087,8 +2088,8 @@ linux_dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sgl, switch (direction) { case DMA_BIDIRECTIONAL: - bus_dmamap_sync(priv->dmat, sgl->dma_map, BUS_DMASYNC_POSTREAD); - bus_dmamap_sync(priv->dmat, sgl->dma_map, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(priv->dmat, sgl->dma_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); break; case DMA_TO_DEVICE: bus_dmamap_sync(priv->dmat, sgl->dma_map, BUS_DMASYNC_POSTWRITE);
