Index | Thread | Search

From:
Mark Kettenis <mark.kettenis@xs4all.nl>
Subject:
Re: mbuf dma 64 bit
To:
Alexander Bluhm <bluhm@openbsd.org>
Cc:
tech@openbsd.org
Date:
Fri, 13 Feb 2026 11:37:27 +0100

Download raw body.

Thread
> Date: Thu, 12 Feb 2026 18:11:17 -0500
> From: Alexander Bluhm <bluhm@openbsd.org>
> 
> On Thu, Feb 12, 2026 at 12:23:19AM +0100, Mark Kettenis wrote:
> > > Date: Wed, 11 Feb 2026 16:43:16 -0500
> > > From: Alexander Bluhm <bluhm@openbsd.org>
> > > 
> > > Hi,
> > > 
> > > Allow to allocate mbufs with physical address above 4 GB.  If any
> > > network driver does not support 64 bit dma, the existing restrictions
> > > are used.
> > > 
> > > I have added the IFXF_MBUF_64BIT flag to all drivers I could test.
> > > 
> > > There is no solution for hotplug devices yet.  And I have not tested
> > > USB network.
> > > 
> > > Is this diff the right direction?
> > 
> > Maybe, but I think you're running ahead a bit too fast here.  The
> > solution for hotplug devices is probably bounce buffers.  But those
> > still need a bit of work.  We have a diff for amd64 (that still needs
> > some work) but there are other 64-bit architectures with DMA
> > constraints.  And ideally we'd audit most of our network drivers
> > before we go this route.  Or at least the subset that is likely to be
> > involved in hotplug scenarios.
> 
> This diff is not meant for immediate commit.  More a collection
> of things we need.
> 
> I have added USB hotplug as discussed in the hackroom.  If the
> controller does not support 64 bit DMA, we restrict mbufs to below
> 4 GB.  Still not clear what to do with PCI hotplug and how relevant
> this is.  Maybe bounce buffers just for them?

USB hotplug isn't an issue.  I keep getting confused by this myself,
but our USB stack already uses its own buffers that it copies mbufs
into before it does DMA.  If the USB controller isn't 64-bit capable,
those buffers are allocated from DMA-reachable memory.  We effectively
USB drivers are already using bounce buffers.

So the problem is hotplug PCI (CardBus, ExpressCard, hotplug-capable
servers).

> > A few comments om (parts of ) the diff down below.
> 
> > > +void
> > > +mbuf_dma_64bit_enable(void)
> > > +{
> > > +	struct ifnet *ifp;
> > > +
> > > +	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
> > > +		if (!ISSET(ifp->if_xflags, IFXF_MBUF_64BIT)) {
> > > +			printf("%s: restrict all mbufs to low memory\n",
> > > +			    ifp->if_xname);
> > > +			return;
> > > +		}
> > > +	}
> > > +
> > > +	printf("enable mbufs in high memory\n");
> > > +	m_pool_constraints(0, ULONG_MAX);
> > > +}
> > > +
> > 
> > I hope those are just debug printfs.
> 
> I think we should keep the restrict message.  If a system is not
> capable to run with high mbufs, we should inform the user what
> causes trouble.  At least until we have figured out how to deal
> with all corner cases.  The positive meassage will be rmeoved before
> commit.

Well, it is the unrestricted case that is "dangerous".

> > > @@ -746,7 +749,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t t,
> > >  		 */
> > >  		pmap_extract(pmap, vaddr, (paddr_t *)&curaddr);
> > >  
> > > -		if (curaddr > dma_constraint.ucr_high &&
> > > +		if (curaddr > constraint->ucr_high &&
> > >  		    (map->_dm_flags & BUS_DMA_64BIT) == 0)
> > >  			panic("Non dma-reachable buffer at curaddr %#lx(raw)",
> > >  			    curaddr);
> > 
> > This is wrong.  If a driver gets an mbuf in high memory, but didn't
> > set BUS_DMA_64BIT, we should still panic.  I don't think you need this
> > bit and it conflicts with the bounce buffer stuff.
> 
> fixed
> 
> > > Index: arch/amd64/amd64/machdep.c
> > > ===================================================================
> > > RCS file: /data/mirror/openbsd/cvs/src/sys/arch/amd64/amd64/machdep.c,v
> > > diff -u -p -r1.306 machdep.c
> > > --- arch/amd64/amd64/machdep.c	24 Nov 2025 17:20:40 -0000	1.306
> > > +++ arch/amd64/amd64/machdep.c	11 Feb 2026 21:19:27 -0000
> > > @@ -218,9 +218,11 @@ struct vm_map *phys_map = NULL;
> > >  /* UVM constraint ranges. */
> > >  struct uvm_constraint_range  isa_constraint = { 0x0, 0x00ffffffUL };
> > >  struct uvm_constraint_range  dma_constraint = { 0x0, 0xffffffffUL };
> > > +struct uvm_constraint_range  mbuf_constraint = { 0x0, 0xffffffffUL };
> > >  struct uvm_constraint_range *uvm_md_constraints[] = {
> > >      &isa_constraint,
> > >      &dma_constraint,
> > > +    &mbuf_constraint,
> > >      NULL,
> > >  };
> > 
> > The uvm_md_constraints[] array is used in uvm to divide up the memory
> > in regions.  The mbuf_constraint isn't a new region.  It is either the
> > same as dma_constraint or equivalent to no_constraint.
> > 
> > One might argue that mbuf_constraint should actually just be a pointer
> > to one those.
> 
> Is the new diff better?

Seems reasonable to me.

> > Are we sure older em(4) variants do actually support 64-bit DMA?
> 
> I have a machine with these, tests currently running.
> 
> em0 at pci2 dev 0 function 0 "Intel 82571EB" rev 0x06: apic 2 int 8, address 00:1b:21:7b:d1:10
> em2 at pci3 dev 0 function 0 "Intel 82580" rev 0x01: msi, address 90:e2:ba:78:7c:f0
> em6 at pci4 dev 0 function 0 "Intel 82576" rev 0x01: msi, address 00:1b:21:da:f6:ec
> em8 at pci5 dev 0 function 0 "Intel I350" rev 0x01: msi, address 00:25:90:e7:ec:7c
> em14 at pci11 dev 0 function 0 "Intel 82576" rev 0x01: msi, address 00:1b:21:60:58:28
> em16 at pci16 dev 0 function 0 "Intel 82571EB" rev 0x06: apic 3 int 20, address 00:50:c2:01:f4:60
> 
> Do you think these variants are sufficient or do you have some more?

It's the older stuff that I'm worried about.  Looking at the Linux
e1000 driver it seems that some of the older PCI devices have issues
with 64-bit DMA.  So they only "enable" it on PCI-X devices.  Now
Linux has the newer PCIe variants in its e1000e driver and enables
64-bit DMA unconditionally in that driver.  So we should enable it for
PCIe devices as well.  So setting the flags if sc->hw.bus_type is
em_bus_type_pcix or em_bus_type_pci_express is probably what we need.

> > I don't expect any issue with adding those BUS_DMA_64BIT to this
> > driver.  You should also add those to the bus_dmamem_alloc(9) calls
> > though.  Can you send this out as a separate diff?
> 
> bus_dmamem_alloc() BUS_DMA_64BIT added.
> 
> I would like to keep it as a single diff for easier testing.  If
> someone wants to review a single driver, I can commit it separately.
> If nobody cares, I will beg for OKs in separate diffs.

Getting the driver bits in will help the bounce buffers.  And I don't
think the rest of this diff should be considered before we have bounce
buffers.

> bluhm
> 
> Index: arch/amd64/amd64/autoconf.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/arch/amd64/amd64/autoconf.c,v
> diff -u -p -r1.59 autoconf.c
> --- arch/amd64/amd64/autoconf.c	12 Nov 2025 10:00:27 -0000	1.59
> +++ arch/amd64/amd64/autoconf.c	12 Feb 2026 22:20:00 -0000
> @@ -60,6 +60,12 @@
>  #include <netinet/in.h>
>  #include <netinet/if_ether.h>
>  
> +#include <machine/bus.h>
> +#include <dev/usb/usb.h>
> +#include <dev/usb/usbdi.h>
> +#include <dev/usb/usbdivar.h>
> +#include <dev/usb/usb_mem.h>
> +
>  #include <machine/cpu.h>
>  #include <machine/cpufunc.h>
>  #include <machine/biosvar.h>
> @@ -108,6 +114,27 @@ unmap_startup(void)
>  	} while (p < (vaddr_t)endboot);
>  }
>  
> +void
> +mbuf_dma_64bit_enable(void)
> +{
> +	struct ifnet *ifp;
> +
> +	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
> +		if (!ISSET(ifp->if_xflags, IFXF_MBUF_64BIT)) {
> +			printf("%s: restrict all mbufs to low memory\n",
> +			    ifp->if_xname);
> +			return;
> +		}
> +	}
> +	if (!usb_mbuf_dma_64bit) {
> +		printf("usb: restrict all mbufs to low memory\n");
> +		return;
> +	}
> +
> +	printf("enable mbufs in high memory\n");
> +	m_pool_noconstraints();
> +}
> +
>  /*
>   * Determine i/o configuration for a machine.
>   */
> @@ -123,6 +150,8 @@ cpu_configure(void)
>  		panic("configure: mainbus not configured");
>  
>  	intr_printconfig();
> +
> +	mbuf_dma_64bit_enable();
>  
>  #if NIOAPIC > 0
>  	lapic_set_lvt();
> Index: dev/pci/if_bnxt.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_bnxt.c,v
> diff -u -p -r1.65 if_bnxt.c
> --- dev/pci/if_bnxt.c	11 Feb 2026 09:35:07 -0000	1.65
> +++ dev/pci/if_bnxt.c	12 Feb 2026 22:20:00 -0000
> @@ -642,7 +642,7 @@ bnxt_attach(struct device *parent, struc
>  	strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
>  	ifp->if_softc = sc;
>  	ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
> -	ifp->if_xflags = IFXF_MPSAFE;
> +	ifp->if_xflags = IFXF_MPSAFE | IFXF_MBUF_64BIT;
>  	ifp->if_ioctl = bnxt_ioctl;
>  	ifp->if_qstart = bnxt_start;
>  	ifp->if_watchdog = bnxt_watchdog;
> Index: dev/pci/if_em.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_em.c,v
> diff -u -p -r1.379 if_em.c
> --- dev/pci/if_em.c	14 Jul 2025 11:52:43 -0000	1.379
> +++ dev/pci/if_em.c	12 Feb 2026 22:20:00 -0000
> @@ -1990,7 +1990,7 @@ em_setup_interface(struct em_softc *sc)
>  	strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
>  	ifp->if_softc = sc;
>  	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
> -	ifp->if_xflags = IFXF_MPSAFE;
> +	ifp->if_xflags = IFXF_MPSAFE | IFXF_MBUF_64BIT;
>  	ifp->if_ioctl = em_ioctl;
>  	ifp->if_qstart = em_start;
>  	ifp->if_watchdog = em_watchdog;
> @@ -2158,7 +2158,8 @@ em_dma_malloc(struct em_softc *sc, bus_s
>  	int r;
>  
>  	r = bus_dmamap_create(sc->sc_dmat, size, 1,
> -	    size, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &dma->dma_map);
> +	    size, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
> +	    &dma->dma_map);
>  	if (r != 0)
>  		return (r);
>  
> @@ -2250,10 +2251,11 @@ em_setup_transmit_structures(struct em_s
>  			pkt = &que->tx.sc_tx_pkts_ring[i];
>  			error = bus_dmamap_create(sc->sc_dmat, EM_TSO_SIZE,
>  			    EM_MAX_SCATTER / (sc->pcix_82544 ? 2 : 1),
> -			    EM_TSO_SEG_SIZE, 0, BUS_DMA_NOWAIT, &pkt->pkt_map);
> +			    EM_TSO_SEG_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_64BIT,
> +			    &pkt->pkt_map);
>  			if (error != 0) {
> -				printf("%s: Unable to create TX DMA map\n",
> -				    DEVNAME(sc));
> +				printf("%s: Unable to create TX DMA map, "
> +				    "error %d\n", DEVNAME(sc), error);
>  				goto fail;
>  			}
>  		}
> @@ -2772,11 +2774,11 @@ em_allocate_receive_structures(struct em
>  			pkt = &que->rx.sc_rx_pkts_ring[i];
>  
>  			error = bus_dmamap_create(sc->sc_dmat, EM_MCLBYTES, 1,
> -			    EM_MCLBYTES, 0, BUS_DMA_NOWAIT, &pkt->pkt_map);
> +			    EM_MCLBYTES, 0, BUS_DMA_NOWAIT | BUS_DMA_64BIT,
> +			    &pkt->pkt_map);
>  			if (error != 0) {
> -				printf("%s: em_allocate_receive_structures: "
> -				    "bus_dmamap_create failed; error %u\n",
> -				    DEVNAME(sc), error);
> +				printf("%s: Unable to create RX DMA map, "
> +				    "error %d\n", DEVNAME(sc), error);
>  				goto fail;
>  			}
>  
> Index: dev/pci/if_ice.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_ice.c,v
> diff -u -p -r1.66 if_ice.c
> --- dev/pci/if_ice.c	18 Nov 2025 09:13:55 -0000	1.66
> +++ dev/pci/if_ice.c	12 Feb 2026 22:20:00 -0000
> @@ -1321,7 +1321,7 @@ ice_alloc_dma_mem(struct ice_hw *hw, str
>  		goto fail;
>  
>  	err = bus_dmamem_alloc(mem->tag, size, 1, 0, &mem->seg, 1, &nsegs,
> -	    BUS_DMA_NOWAIT | BUS_DMA_ZERO);
> +	    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_64BIT);
>  	if (err || nsegs != 1)
>  		goto fail_1;
>  
> @@ -30657,7 +30657,7 @@ ice_attach_hook(struct device *self)
>  	ifp->if_softc = sc;
>  	strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
>  	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
> -	ifp->if_xflags = IFXF_MPSAFE;
> +	ifp->if_xflags = IFXF_MPSAFE | IFXF_MBUF_64BIT;
>  	ifp->if_ioctl = ice_ioctl;
>  	ifp->if_qstart = ice_start;
>  	ifp->if_watchdog = ice_watchdog;
> Index: dev/pci/if_igc.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_igc.c,v
> diff -u -p -r1.30 if_igc.c
> --- dev/pci/if_igc.c	17 Dec 2025 01:14:42 -0000	1.30
> +++ dev/pci/if_igc.c	12 Feb 2026 22:20:00 -0000
> @@ -737,11 +737,11 @@ igc_dma_malloc(struct igc_softc *sc, bus
>  
>  	dma->dma_tag = os->os_pa.pa_dmat;
>  
> -	if (bus_dmamap_create(dma->dma_tag, size, 1, size, 0, BUS_DMA_NOWAIT,
> -	    &dma->dma_map))
> +	if (bus_dmamap_create(dma->dma_tag, size, 1, size, 0,
> +	    BUS_DMA_NOWAIT | BUS_DMA_64BIT, &dma->dma_map))
>  		return 1;
>  	if (bus_dmamem_alloc(dma->dma_tag, size, PAGE_SIZE, 0, &dma->dma_seg,
> -	    1, &dma->dma_nseg, BUS_DMA_NOWAIT))
> +	    1, &dma->dma_nseg, BUS_DMA_NOWAIT | BUS_DMA_64BIT))
>  		goto destroy;
>  	if (bus_dmamem_map(dma->dma_tag, &dma->dma_seg, dma->dma_nseg, size,
>  	    &dma->dma_vaddr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT))
> @@ -796,7 +796,7 @@ igc_setup_interface(struct igc_softc *sc
>  	ifp->if_softc = sc;
>  	strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
>  	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
> -	ifp->if_xflags = IFXF_MPSAFE;
> +	ifp->if_xflags = IFXF_MPSAFE | IFXF_MBUF_64BIT;
>  	ifp->if_ioctl = igc_ioctl;
>  	ifp->if_qstart = igc_start;
>  	ifp->if_watchdog = igc_watchdog;
> @@ -1855,10 +1855,11 @@ igc_allocate_transmit_buffers(struct igc
>  	for (i = 0; i < sc->num_tx_desc; i++) {
>  		txbuf = &txr->tx_buffers[i];
>  		error = bus_dmamap_create(txr->txdma.dma_tag, IGC_TSO_SIZE,
> -		    IGC_MAX_SCATTER, PAGE_SIZE, 0, BUS_DMA_NOWAIT, &txbuf->map);
> +		    IGC_MAX_SCATTER, PAGE_SIZE, 0,
> +		    BUS_DMA_NOWAIT | BUS_DMA_64BIT, &txbuf->map);
>  		if (error != 0) {
> -			printf("%s: Unable to create TX DMA map\n",
> -			    DEVNAME(sc));
> +			printf("%s: Unable to create TX DMA map, error %d\n",
> +			    DEVNAME(sc), error);
>  			goto fail;
>  		}
>  	}
> @@ -2161,10 +2162,10 @@ igc_allocate_receive_buffers(struct igc_
>  	for (i = 0; i < sc->num_rx_desc; i++, rxbuf++) {
>  		error = bus_dmamap_create(rxr->rxdma.dma_tag,
>  		    sc->rx_mbuf_sz, 1, sc->rx_mbuf_sz, 0,
> -		    BUS_DMA_NOWAIT, &rxbuf->map);
> +		    BUS_DMA_NOWAIT | BUS_DMA_64BIT, &rxbuf->map);
>  		if (error) {
> -			printf("%s: Unable to create RX DMA map\n",
> -			    DEVNAME(sc));
> +			printf("%s: Unable to create RX DMA map, error %d\n",
> +			    DEVNAME(sc), error);
>  			goto fail;
>  		}
>  	}
> Index: dev/pci/if_ix.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_ix.c,v
> diff -u -p -r1.222 if_ix.c
> --- dev/pci/if_ix.c	11 Nov 2025 17:43:18 -0000	1.222
> +++ dev/pci/if_ix.c	12 Feb 2026 22:20:00 -0000
> @@ -1929,7 +1929,7 @@ ixgbe_setup_interface(struct ix_softc *s
>  	strlcpy(ifp->if_xname, sc->dev.dv_xname, IFNAMSIZ);
>  	ifp->if_softc = sc;
>  	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
> -	ifp->if_xflags = IFXF_MPSAFE;
> +	ifp->if_xflags = IFXF_MPSAFE | IFXF_MBUF_64BIT;
>  	ifp->if_ioctl = ixgbe_ioctl;
>  	ifp->if_qstart = ixgbe_start;
>  	ifp->if_timer = 0;
> @@ -2087,7 +2087,7 @@ ixgbe_dma_malloc(struct ix_softc *sc, bu
>  
>  	dma->dma_tag = os->os_pa.pa_dmat;
>  	r = bus_dmamap_create(dma->dma_tag, size, 1,
> -	    size, 0, BUS_DMA_NOWAIT, &dma->dma_map);
> +	    size, 0, BUS_DMA_NOWAIT | BUS_DMA_64BIT, &dma->dma_map);
>  	if (r != 0) {
>  		printf("%s: ixgbe_dma_malloc: bus_dmamap_create failed; "
>  		       "error %u\n", ifp->if_xname, r);
> @@ -2095,7 +2095,7 @@ ixgbe_dma_malloc(struct ix_softc *sc, bu
>  	}
>  
>  	r = bus_dmamem_alloc(dma->dma_tag, size, PAGE_SIZE, 0, &dma->dma_seg,
> -	    1, &dma->dma_nseg, BUS_DMA_NOWAIT);
> +	    1, &dma->dma_nseg, BUS_DMA_NOWAIT | BUS_DMA_64BIT);
>  	if (r != 0) {
>  		printf("%s: ixgbe_dma_malloc: bus_dmamem_alloc failed; "
>  		       "error %u\n", ifp->if_xname, r);
> @@ -2293,11 +2293,11 @@ ixgbe_allocate_transmit_buffers(struct i
>  		txbuf = &txr->tx_buffers[i];
>  		error = bus_dmamap_create(txr->txdma.dma_tag, MAXMCLBYTES,
>  			    sc->num_segs, PAGE_SIZE, 0,
> -			    BUS_DMA_NOWAIT, &txbuf->map);
> +			    BUS_DMA_NOWAIT | BUS_DMA_64BIT, &txbuf->map);
>  
>  		if (error != 0) {
> -			printf("%s: Unable to create TX DMA map\n",
> -			    ifp->if_xname);
> +			printf("%s: Unable to create TX DMA map, error %d\n",
> +			    ifp->if_xname, error);
>  			goto fail;
>  		}
>  	}
> @@ -2776,10 +2776,10 @@ ixgbe_allocate_receive_buffers(struct ix
>  	rxbuf = rxr->rx_buffers;
>  	for (i = 0; i < sc->num_rx_desc; i++, rxbuf++) {
>  		error = bus_dmamap_create(rxr->rxdma.dma_tag, 16 * 1024, 1,
> -		    16 * 1024, 0, BUS_DMA_NOWAIT, &rxbuf->map);
> +		    16 * 1024, 0, BUS_DMA_NOWAIT | BUS_DMA_64BIT, &rxbuf->map);
>  		if (error) {
> -			printf("%s: Unable to create Pack DMA map\n",
> -			    ifp->if_xname);
> +			printf("%s: Unable to create RX DMA map, error %d\n",
> +			    ifp->if_xname, error);
>  			goto fail;
>  		}
>  	}
> Index: dev/pci/if_ixl.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_ixl.c,v
> diff -u -p -r1.114 if_ixl.c
> --- dev/pci/if_ixl.c	4 Dec 2025 16:51:29 -0000	1.114
> +++ dev/pci/if_ixl.c	12 Feb 2026 22:20:00 -0000
> @@ -1914,7 +1914,7 @@ ixl_attach(struct device *parent, struct
>  
>  	ifp->if_softc = sc;
>  	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
> -	ifp->if_xflags = IFXF_MPSAFE;
> +	ifp->if_xflags = IFXF_MPSAFE | IFXF_MBUF_64BIT;
>  	ifp->if_ioctl = ixl_ioctl;
>  	ifp->if_qstart = ixl_start;
>  	ifp->if_watchdog = ixl_watchdog;
> Index: dev/pv/if_vio.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pv/if_vio.c,v
> diff -u -p -r1.78 if_vio.c
> --- dev/pv/if_vio.c	15 Jan 2026 09:06:19 -0000	1.78
> +++ dev/pv/if_vio.c	12 Feb 2026 22:20:00 -0000
> @@ -750,7 +750,7 @@ negotiate:
>  
>  	ifp->if_capabilities = 0;
>  	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
> -	ifp->if_xflags = IFXF_MPSAFE;
> +	ifp->if_xflags = IFXF_MPSAFE | IFXF_MBUF_64BIT;
>  #if NVLAN > 0
>  	ifp->if_capabilities |= IFCAP_VLAN_MTU;
>  	ifp->if_capabilities |= IFCAP_VLAN_HWOFFLOAD;
> Index: dev/usb/ehci.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/usb/ehci.c,v
> diff -u -p -r1.222 ehci.c
> --- dev/usb/ehci.c	11 Oct 2024 09:55:24 -0000	1.222
> +++ dev/usb/ehci.c	12 Feb 2026 22:20:00 -0000
> @@ -340,6 +340,8 @@ ehci_init(struct ehci_softc *sc)
>  		    0, "ehcixfer", NULL);
>  	}
>  
> +	usb_mbuf_dma_64bit = 0;
> +
>  	/* frame list size at default, read back what we got and use that */
>  	switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) {
>  	case 0:
> Index: dev/usb/ohci.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/usb/ohci.c,v
> diff -u -p -r1.165 ohci.c
> --- dev/usb/ohci.c	12 Apr 2022 19:41:11 -0000	1.165
> +++ dev/usb/ohci.c	12 Feb 2026 22:20:00 -0000
> @@ -730,6 +730,8 @@ ohci_init(struct ohci_softc *sc)
>  		    0, "ohcixfer", NULL);
>  	}
>  
> +	usb_mbuf_dma_64bit = 0;
> +
>  	/* XXX determine alignment by R/W */
>  	/* Allocate the HCCA area. */
>  	err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE, OHCI_HCCA_ALIGN,
> Index: dev/usb/uhci.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/usb/uhci.c,v
> diff -u -p -r1.156 uhci.c
> --- dev/usb/uhci.c	12 Apr 2022 19:41:11 -0000	1.156
> +++ dev/usb/uhci.c	12 Feb 2026 22:20:00 -0000
> @@ -373,6 +373,8 @@ uhci_init(struct uhci_softc *sc)
>  		    0, "uhcixfer", NULL);
>  	}
>  
> +	usb_mbuf_dma_64bit = 0;
> +
>  	/* Restore saved SOF. */
>  	UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof);
>  
> Index: dev/usb/usb_mem.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/usb/usb_mem.c,v
> diff -u -p -r1.36 usb_mem.c
> --- dev/usb/usb_mem.c	8 Oct 2024 19:42:31 -0000	1.36
> +++ dev/usb/usb_mem.c	12 Feb 2026 22:20:00 -0000
> @@ -73,6 +73,8 @@ usbd_status	usb_block_allocmem(bus_dma_t
>  		    struct usb_dma_block **, int);
>  void		usb_block_freemem(struct usb_dma_block *);
>  
> +int usb_mbuf_dma_64bit = 1;
> +
>  LIST_HEAD(, usb_dma_block) usb_blk_freelist =
>  	LIST_HEAD_INITIALIZER(usb_blk_freelist);
>  int usb_blk_nfree = 0;
> Index: dev/usb/usb_mem.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/usb/usb_mem.h,v
> diff -u -p -r1.18 usb_mem.h
> --- dev/usb/usb_mem.h	8 Oct 2024 19:42:31 -0000	1.18
> +++ dev/usb/usb_mem.h	12 Feb 2026 22:20:00 -0000
> @@ -47,6 +47,8 @@ struct usb_dma_block {
>  	LIST_ENTRY(usb_dma_block) next;
>  };
>  
> +extern int usb_mbuf_dma_64bit;
> +
>  #define DMAADDR(dma, o) ((dma)->block->map->dm_segs[0].ds_addr + (dma)->offs + (o))
>  #define KERNADDR(dma, o) \
>  	((void *)((char *)((dma)->block->kaddr + (dma)->offs) + (o)))
> Index: dev/usb/xhci.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/usb/xhci.c,v
> diff -u -p -r1.136 xhci.c
> --- dev/usb/xhci.c	1 Mar 2025 14:43:03 -0000	1.136
> +++ dev/usb/xhci.c	12 Feb 2026 22:20:00 -0000
> @@ -329,7 +329,10 @@ xhci_init(struct xhci_softc *sc)
>  
>  	hcr = XREAD4(sc, XHCI_HCCPARAMS);
>  	sc->sc_ctxsize = XHCI_HCC_CSZ(hcr) ? 64 : 32;
> -	sc->sc_bus.dmaflags |= XHCI_HCC_AC64(hcr) ? BUS_DMA_64BIT : 0;
> +	if (XHCI_HCC_AC64(hcr))
> +		sc->sc_bus.dmaflags |= BUS_DMA_64BIT;
> +	else
> +		usb_mbuf_dma_64bit = 0;
>  	DPRINTF(("%s: %d bytes context\n", DEVNAME(sc), sc->sc_ctxsize));
>  
>  #ifdef XHCI_DEBUG
> Index: kern/uipc_mbuf.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_mbuf.c,v
> diff -u -p -r1.304 uipc_mbuf.c
> --- kern/uipc_mbuf.c	5 Feb 2026 03:26:00 -0000	1.304
> +++ kern/uipc_mbuf.c	12 Feb 2026 22:20:00 -0000
> @@ -1480,6 +1480,17 @@ m_pool_init(struct pool *pp, u_int size,
>  	pool_set_constraints(pp, &kp_dma_contig);
>  }
>  
> +void
> +m_pool_noconstraints(void)
> +{
> +	int i;
> +
> +	pool_set_constraints(&mbpool, &kp_mbuf_contig);
> +
> +	for (i = 0; i < nitems(mclsizes); i++)
> +		pool_set_constraints(&mclpools[i], &kp_mbuf_contig);
> +}
> +
>  u_int
>  m_pool_used(void)
>  {
> Index: net/if.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.h,v
> diff -u -p -r1.223 if.h
> --- net/if.h	9 Dec 2025 03:33:06 -0000	1.223
> +++ net/if.h	12 Feb 2026 22:20:00 -0000
> @@ -232,6 +232,7 @@ struct if_status_description {
>  #define	IFXF_AUTOCONF4		0x80	/* [N] v4 autoconf (aka dhcp) enabled */
>  #define	IFXF_MONITOR		0x100	/* [N] only used for bpf */
>  #define	IFXF_LRO		0x200	/* [N] TCP large recv offload */
> +#define	IFXF_MBUF_64BIT		0x400	/* [I] mbuf with 64 bit DMA supported */
>  
>  #define	IFXF_CANTCHANGE \
>  	(IFXF_MPSAFE|IFXF_CLONED)
> Index: sys/mbuf.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/sys/mbuf.h,v
> diff -u -p -r1.269 mbuf.h
> --- sys/mbuf.h	5 Feb 2026 03:26:00 -0000	1.269
> +++ sys/mbuf.h	12 Feb 2026 22:20:00 -0000
> @@ -441,6 +441,7 @@ void	m_align(struct mbuf *, int);
>  struct mbuf *m_clget(struct mbuf *, int, u_int);
>  void	m_extref(struct mbuf *, struct mbuf *);
>  void	m_pool_init(struct pool *, u_int, u_int, const char *);
> +void	m_pool_noconstraints(void);
>  u_int	m_pool_used(void);
>  void	m_extfree_pool(caddr_t, u_int, void *);
>  void	m_adj(struct mbuf *, int);
> Index: uvm/uvm_extern.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/uvm/uvm_extern.h,v
> diff -u -p -r1.187 uvm_extern.h
> --- uvm/uvm_extern.h	13 Nov 2025 10:55:51 -0000	1.187
> +++ uvm/uvm_extern.h	12 Feb 2026 22:20:00 -0000
> @@ -358,6 +358,7 @@ extern const struct kmem_pa_mode kp_zero
>  extern const struct kmem_pa_mode kp_dma;
>  extern const struct kmem_pa_mode kp_dma_contig;
>  extern const struct kmem_pa_mode kp_dma_zero;
> +extern const struct kmem_pa_mode kp_mbuf_contig;
>  extern const struct kmem_pa_mode kp_pageable;
>  extern const struct kmem_pa_mode kp_none;
>  
> Index: uvm/uvm_km.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/uvm/uvm_km.c,v
> diff -u -p -r1.159 uvm_km.c
> --- uvm/uvm_km.c	13 Nov 2025 10:55:51 -0000	1.159
> +++ uvm/uvm_km.c	12 Feb 2026 22:20:00 -0000
> @@ -745,6 +745,11 @@ const struct kmem_pa_mode kp_dma_zero = 
>  	.kp_zero = 1
>  };
>  
> +const struct kmem_pa_mode kp_mbuf_contig = {
> +	.kp_constraint = &no_constraint,
> +	.kp_maxseg = 1
> +};
> +
>  const struct kmem_pa_mode kp_zero = {
>  	.kp_constraint = &no_constraint,
>  	.kp_zero = 1
> 
>