aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2026-01-23 19:14:18 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2026-02-09 21:40:47 +0000
commitb615b4805a9ce83b9b86dd66d46a9f220f9f89c6 (patch)
tree444558a1465b7394ad0cb33e8aaff51b99fffe71
parent840f478eed2ab18abd1088aa12587bb708a46b56 (diff)
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 MFC after: 3 days Observed with: iwlwifi mld Reviewed by: dumbbell Differential Revision: https://reviews.freebsd.org/D54841
-rw-r--r--sys/compat/linuxkpi/common/src/linux_pci.c21
1 files 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 9e4fad45433a..612a2cb5f46b 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);