The branch stable/15 has been updated by bz:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=9c0f88c33ce02d8b842e7e75ba7b0beb7edebcbc

commit 9c0f88c33ce02d8b842e7e75ba7b0beb7edebcbc
Author:     Bjoern A. Zeeb <[email protected]>
AuthorDate: 2026-01-23 19:14:18 +0000
Commit:     Bjoern A. Zeeb <[email protected]>
CommitDate: 2026-02-26 23:02:27 +0000

    LinuxKPI: expand dma_sync_single_for_cpu() in lkpi_dma_unmap()
    
    In case lkpi_dma_unmap() would call dma_sync_single_for_cpu() we get
    into a lock recursion which will trigger a panic with debug kernels.
    
    It would be hard to provide an internal "locked" version for
    dma_sync_single_for_cpu().  In the old days this would not have
    been a problem but (long before we added the missing sync calls)
    some locks got folded into one in a6619e8d9c1a3.
    
    Sponsored by:   The FreeBSD Foundation
    Observed with:  iwlwifi mld
    Reviewed by:    dumbbell
    Differential Revision:  https://reviews.freebsd.org/D54841
    
    (cherry picked from commit b615b4805a9ce83b9b86dd66d46a9f220f9f89c6)
---
 sys/compat/linuxkpi/common/src/linux_pci.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c 
b/sys/compat/linuxkpi/common/src/linux_pci.c
index cf8a6ffeb46c..c8d1989f669b 100644
--- a/sys/compat/linuxkpi/common/src/linux_pci.c
+++ b/sys/compat/linuxkpi/common/src/linux_pci.c
@@ -1720,9 +1720,26 @@ lkpi_dma_unmap(struct device *dev, dma_addr_t dma_addr, 
size_t len,
        }
        LINUX_DMA_PCTRIE_REMOVE(&priv->ptree, dma_addr);
 
-       if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
-               dma_sync_single_for_cpu(dev, dma_addr, len, direction);
+       if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) != 0)
+               goto skip_sync;
 
+       /* 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);
+               break;
+       case DMA_TO_DEVICE:
+               bus_dmamap_sync(obj->dmat, obj->dmamap, BUS_DMASYNC_POSTWRITE);
+               break;
+       case DMA_FROM_DEVICE:
+               bus_dmamap_sync(obj->dmat, obj->dmamap, BUS_DMASYNC_POSTREAD);
+               break;
+       default:
+               break;
+       }
+
+skip_sync:
        bus_dmamap_unload(obj->dmat, obj->dmamap);
        bus_dmamap_destroy(obj->dmat, obj->dmamap);
        DMA_PRIV_UNLOCK(priv);

Reply via email to