Re: iwx 64-bit dma

Mark Kettenis <[email protected]> Sat, 01 Aug 2026 15:25:52 +0200
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
> Date: Fri, 31 Jul 2026 07:40:01 -0700
> From: Chris Cappuccio <[email protected]>
> 
> Mark Kettenis [[email protected]] wrote:
> > > Date: Thu, 30 Jul 2026 18:33:49 -0700
> > > From: Chris Cappuccio <[email protected]>
> > > 
> > > Theo de Raadt [[email protected]] wrote:
> > > > 
> > > > The diff in question which adds BUS_DMA_64BIT is a declaration to
> > > > the higher-level code that _all_ chipsets supported by this driver can
> > > > work with 64 bit-addressable memory if the higher levels provide it.
> > > > 
> > > 
> > > Linux iwlwifi has a 36-bit dma limit for older hardware. For the
> > > AX200/201 and the AX210/211 it's 64-bit all the way. So iwx is
> > > doing the right thing.
> > > 
> > > However, there is a bug with the AX200/201 dma engine crossing 32-bit
> > > boundaries:
> > > 
> > > https://code.opensuse.org/kernel/kernel-source/blob/5377a688dcc5c526f0a5df6d91df22d8b4f2dce6/f/patches.suse/iwlwifi-pcie-extend-hardware-workaround-to-context-i.patch
> > > 
> > > To avoid triggering it, we'd need to do something like this with
> > > any post-IOMMU addresses:
> > > 
> > > iwx_crosses_4g_boundary(struct iwx_softc *sc, bus_addr_t addr, bus_size_t len) {
> > > 	if (sc->sc_device_family != IWX_DEVICE_FAMILY_22000)
> > > 		return 0;
> > > 
> > > 	return (addr >> 32) != ((addr + len) >> 32);
> > > }
> > > ...
> > > 	for (i = 0; i < map->dm_nsegs; i++) {
> > > 		if (iwx_crosses_4g_boundary(sc, map->dm_segs[i].ds_addr,
> > > 		    map->dm_segs[i].ds_len)) {
> > > 			/* remap */
> > > 		}
> > > 	}
> > 
> > The right way to solve that issue is to specify a non-zero boundary
> > when calling bus_dmamap_create() to create the DMA map.
> 
> Maybe, maybe not. It's some kind of bug in the hardware dma controller.
> 
> The bug is first described in linux c4a786b32621850775dedd1a329de0c060f9c904
> as "if the TB ends up on a 32-bit boundary, then the next TB may
> may be accessed with the wrong address"
> 
> If this is accurate, it's describing an internal bug affecting the
> next buffer.
> 
> A boundary at 1<<32 would prevent access crossing the boundary, but Intel's
> function also prevents access _up_to_ the boundary (such as, a transfer with
> a last byte at 0x........ffffffff)
> 
> So "crosses_4g_boundary" (their name) isn't describing the behavior from
> openbsd or linux, it's describing a hardware problem.
> 
> Someone with one of these would have to force use of these addresses to
> exercise it.

Ah crap.  So not only crossing the boundary triggers the bug, touching
it would as well.  So in theory this could happen even with 32-bit
DMA.  This can't happen on x86 since the top part of the 32-bit
address space doesn't contain any RAM.  But on other architectures
this could happen.

The IOMMU could work around this, since it could choose to not
allocate the page before each boundary for DVA.  At first sight it
seems that an IOMMU implementation that uses extents would already do
this since the extent_alloc(9) man page says:

  The allocated region may begin on a boundary line, but the end of
  the region will not touch nor cross a boundary line.

But only the "will not cross" part is actually implemented.  Or
perhaps their meaning of "will not touch" is different from mine?

Anyway, since this can't be fixed by the bus_dma layer this does
indeed need to be fixed in the driver.