[Bug 297155] LinuxKPI: swapped busdma sync operations in the DMA_TO_DEVICE / DMA_FROM_DEVICE PRE-sync path break streaming DMA when a mapping bounces (breaks ath10k QCA6174 on >4GB machines)

From: <bugzilla-noreply_at_freebsd.org>
Date: Thu, 30 Jul 2026 03:19:52 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=297155

            Bug ID: 297155
           Summary: LinuxKPI: swapped busdma sync operations in the
                    DMA_TO_DEVICE / DMA_FROM_DEVICE PRE-sync path break
                    streaming DMA when a mapping bounces (breaks ath10k
                    QCA6174 on >4GB machines)
           Product: Base System
           Version: CURRENT
          Hardware: amd64
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: kern
          Assignee: bugs@FreeBSD.org
          Reporter: fbsdbugs@westryn.net

Created attachment 273303
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=273303&action=edit
swapped busdma sync operations in the DMA_TO_DEVICE / DMA_FROM_DEVICE

LinuxKPI: fix swapped busdma sync ops in DMA_TO_DEVICE/FROM_DEVICE PRE-sync     

dma_sync_single_for_device() and the PRE-sync switch in                         
linux_dma_map_sg_attrs() transpose the busdma sync operations for the           
DMA_TO_DEVICE and DMA_FROM_DEVICE directions.                                   

Per the Linux DMA API, dma_sync_single_for_device() on a DMA_TO_DEVICE          
mapping must make the CPU's writes visible to the device before it reads        
the buffer. For a bounce buffer that means copying the client buffer into       
the bounce page, which busdma performs on BUS_DMASYNC_PREWRITE (see             
bounce_bus_dmamap_sync() in sys/x86/x86/busdma_bounce.c: PREWRITE does          
bcopy(client -> bounce); PREREAD moves no data). The code instead issued        
BUS_DMASYNC_PREREAD for DMA_TO_DEVICE (a no-op) and BUS_DMASYNC_PREWRITE        
for DMA_FROM_DEVICE.                                                            

The bug is only observable when a streaming mapping actually bounces,           
i.e. a device with a sub-64-bit DMA mask on a machine with RAM above the        
mask limit. Most LinuxKPI drivers use a 64-bit mask and never bounce, so        
the wrong op was a harmless no-op. ath10k(4) (QCA6174) forces a 32-bit          
mask via dma_set_mask_and_coherent(DMA_BIT_MASK(32)); on a >4GB machine         
its BMI request buffer (DMA_TO_DEVICE) is never copied into the bounce          
page, the target never sees the command, and firmware probe fails with:         

    ath10k0: bmi cmd took 3009 jiffies hz 1000 ret -60                          
    ath10k0: could not get target info (-60)                                    
    ath10k0: could not probe fw (-60)                                           

Capping physmem below 4GB (no bounce) or applying this patch both resolve       
it; with the patch ath10k attaches and scans normally at full 16GB.             

The POST-sync paths (dma_sync_single_for_cpu(), linux_dma_unmap_sg_attrs())     
already use the conventional DMA_TO_DEVICE->POSTWRITE /                         
DMA_FROM_DEVICE->POSTREAD mapping; only the two PRE switches were swapped.      
This change makes PRE match. DMA_BIDIRECTIONAL (PREWRITE) is unchanged.

-- 
You are receiving this mail because:
You are the assignee for the bug.