Extracted the relevant code from the x86 arch for addition to the rump
DMA handling. Now a bounce threshold is supported that if exceeded
will trigger use of a bounce buffer rather than the user
buffer. Bounce buffer and user buffer are synchronised during
bus_dmamap_sync(). This feature permits more efficient and transparent
support for disk controllers that only support 32 bit PCI addresses
but used on systems where physical memory addresses exceed 32 bits
(hurd-amd64 and hurd-i386/PAE).
---
debian/patches/dma_bounce_buffers.diff | 621 +++++++++++++++++++++++++
debian/patches/series | 1 +
2 files changed, 622 insertions(+)
create mode 100644 debian/patches/dma_bounce_buffers.diff
diff --git a/debian/patches/dma_bounce_buffers.diff
b/debian/patches/dma_bounce_buffers.diff
new file mode 100644
index 000000000..2dd37ac9e
--- /dev/null
+++ b/debian/patches/dma_bounce_buffers.diff
@@ -0,0 +1,621 @@
+Index: rumpkernel/buildrump.sh/src/sys/rump/dev/lib/libpci/pci_at_mainbus.c
+===================================================================
+--- rumpkernel.orig/buildrump.sh/src/sys/rump/dev/lib/libpci/pci_at_mainbus.c
++++ rumpkernel/buildrump.sh/src/sys/rump/dev/lib/libpci/pci_at_mainbus.c
+@@ -45,6 +45,20 @@ __KERNEL_RCSID(0, "$NetBSD: pci_at_mainb
+
+ #include "pci_user.h"
+
++struct bus_dma_tag rump_bus_dma_tag = {
++#if defined(_LP64) || defined(PAE)
++ ._bounce_thresh = PCI32_DMA_BOUNCE_THRESHOLD,
++#else
++ ._bounce_thresh = 0,
++#endif
++};
++
++#ifdef _LP64
++struct bus_dma_tag rump_bus_dma64_tag = {
++ ._bounce_thresh = 0,
++};
++#endif
++
+ RUMP_COMPONENT(RUMP_COMPONENT_DEV)
+ {
+ extern const struct cdevsw pci_cdevsw;
+@@ -76,9 +90,9 @@ RUMP_COMPONENT(RUMP_COMPONENT_DEV_AFTERM
+ pba.pba_bus = 0;
+ pba.pba_iot = (bus_space_tag_t)0;
+ pba.pba_memt = (bus_space_tag_t)1;
+- pba.pba_dmat = (void *)0x20;
++ pba.pba_dmat = &rump_bus_dma_tag;
+ #ifdef _LP64
+- pba.pba_dmat64 = (void *)0x40;
++ pba.pba_dmat64 = &rump_bus_dma64_tag;
+ #endif
+ pba.pba_flags = PCI_FLAGS_MEM_OKAY |
+ PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY;
+Index: rumpkernel/buildrump.sh/src/sys/rump/dev/lib/libpci/rumpdev_bus_dma.c
+===================================================================
+--- rumpkernel.orig/buildrump.sh/src/sys/rump/dev/lib/libpci/rumpdev_bus_dma.c
++++ rumpkernel/buildrump.sh/src/sys/rump/dev/lib/libpci/rumpdev_bus_dma.c
+@@ -82,11 +82,74 @@ __KERNEL_RCSID(0, "$NetBSD: rumpdev_bus_
+
+ #include "pci_user.h"
+
++#define RUMP_DMA_MIGHT_NEED_BOUNCE 0x01 /* may need bounce
buffers */
++#define RUMP_DMA_HAS_BOUNCE 0x02 /* has bounce buffers */
++#define RUMP_DMA_IS_BOUNCING 0x04 /* is bouncing current
xfer */
++#define RUMP_DMA_BUFTYPE_INVALID 0
++#define RUMP_DMA_BUFTYPE_LINEAR 1
++
++struct rump_bus_dma_cookie {
++
++ int id_flags; /* flags; see below */
++
++ /*
++ * Information about the original buffer used during
++ * DMA map syncs. Note that origibuflen is only used
++ * for RUMP_DMA_BUFTYPE_LINEAR.
++ */
++ void *id_origbuf; /* pointer to orig buffer if
++ bouncing */
++ bus_size_t id_origbuflen; /* ...and size */
++ int id_buftype; /* type of buffer */
++
++ void *id_bouncebuf; /* pointer to the bounce buffer */
++ bus_size_t id_bouncebuflen; /* ...and size */
++ int id_nbouncesegs; /* number of valid bounce segs */
++ bus_dma_segment_t id_bouncesegs[0]; /* array of bounce buffer
++ physical memory segments */
++};
++
+ static int _bus_dmamap_load_buffer (bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct vmspace *, int, bus_addr_t *, int *, int);
+
+ int bus_dmatag_subregion(bus_dma_tag_t tag, bus_addr_t min_addr,
+ bus_addr_t max_addr, bus_dma_tag_t *newtag, int flags);
++
++static int
++_bus_dma_alloc_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map,
++ bus_size_t size, int flags)
++{
++ struct rump_bus_dma_cookie *cookie = map->_dm_cookie;
++ int error = 0;
++
++ KASSERT(cookie != NULL);
++
++ cookie->id_bouncebuflen = round_page(size);
++ error = bus_dmamem_alloc(t, cookie->id_bouncebuflen,
++ PAGE_SIZE, map->_dm_boundary, cookie->id_bouncesegs,
++ map->_dm_segcnt, &cookie->id_nbouncesegs, flags);
++ if (error) {
++ cookie->id_bouncebuflen = 0;
++ cookie->id_nbouncesegs = 0;
++ return error;
++ }
++
++ error = bus_dmamem_map(t, cookie->id_bouncesegs,
++ cookie->id_nbouncesegs, cookie->id_bouncebuflen,
++ (void **)&cookie->id_bouncebuf, flags);
++
++ if (error) {
++ bus_dmamem_free(t, cookie->id_bouncesegs,
++ cookie->id_nbouncesegs);
++ cookie->id_bouncebuflen = 0;
++ cookie->id_nbouncesegs = 0;
++ } else {
++ cookie->id_flags |= RUMP_DMA_HAS_BOUNCE;
++ }
++
++ return (error);
++}
++
+ /*
+ * Common function for DMA map creation. May be called by bus-specific
+ * DMA map creation functions.
+@@ -99,6 +162,7 @@ bus_dmamap_create(bus_dma_tag_t t, bus_s
+ bus_dmamap_t map;
+ void *mapstore;
+ size_t mapsize;
++ int error;
+
+ /*
+ * Allocate and initialize the DMA map. The end of the map
+@@ -123,14 +187,64 @@ bus_dmamap_create(bus_dma_tag_t t, bus_s
+ map->_dm_segcnt = nsegments;
+ map->_dm_maxmaxsegsz = maxsegsz;
+ map->_dm_boundary = boundary;
+- map->_dm_bounce_thresh = 0;
++ map->_dm_bounce_thresh = t->_bounce_thresh;
+ map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT);
++ map->_dm_cookie = NULL;
+ map->dm_maxsegsz = maxsegsz;
+ map->dm_mapsize = 0; /* no valid mappings */
+ map->dm_nsegs = 0;
+
+- *dmamp = map;
+- return (0);
++ error = 0;
++
++ if (map->_dm_bounce_thresh != 0)
++ {
++ /*
++ * Allocate our cookie.
++ */
++ struct rump_bus_dma_cookie *cookie;
++ ssize_t cookiesize;
++ void *cookiestore;
++ cookiesize = sizeof(struct rump_bus_dma_cookie) +
++ (sizeof(bus_dma_segment_t) * map->_dm_segcnt);
++
++ if ((cookiestore = kmem_intr_alloc(cookiesize,
++ (flags & BUS_DMA_NOWAIT) ? KM_NOSLEEP : KM_SLEEP)) == NULL)
++ {
++ error = ENOMEM;
++ }
++ else
++ {
++ cookie = (struct rump_bus_dma_cookie *)cookiestore;
++ cookie->id_flags = RUMP_DMA_MIGHT_NEED_BOUNCE;
++ map->_dm_cookie = cookie;
++
++ error = _bus_dma_alloc_bouncebuf(t, map, size, flags);
++ }
++ }
++
++ if (error)
++ bus_dmamap_destroy(t, map);
++ else
++ {
++ *dmamp = map;
++ }
++
++ return (error);
++}
++
++static void
++_bus_dma_free_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map)
++{
++ struct rump_bus_dma_cookie *cookie = map->_dm_cookie;
++
++ KASSERT(cookie != NULL);
++
++ bus_dmamem_unmap(t, cookie->id_bouncebuf, cookie->id_bouncebuflen);
++ bus_dmamem_free(t, cookie->id_bouncesegs,
++ cookie->id_nbouncesegs);
++ cookie->id_bouncebuflen = 0;
++ cookie->id_nbouncesegs = 0;
++ cookie->id_flags &= ~RUMP_DMA_HAS_BOUNCE;
+ }
+
+ /*
+@@ -140,6 +254,21 @@ bus_dmamap_create(bus_dma_tag_t t, bus_s
+ void
+ bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
+ {
++ struct rump_bus_dma_cookie *cookie = map->_dm_cookie;
++
++ /*
++ * Free any bounce pages this map might hold.
++ */
++ if (cookie != NULL) {
++ if (cookie->id_flags & RUMP_DMA_HAS_BOUNCE)
++ _bus_dma_free_bouncebuf(t, map);
++
++ const ssize_t cookiesize =
++ (sizeof(struct rump_bus_dma_cookie) +
++ (sizeof(bus_dma_segment_t) * map->_dm_segcnt));
++
++ kmem_intr_free(cookie, cookiesize);
++ }
+
+ size_t mapsize = sizeof(*map)
+ + sizeof(bus_dma_segment_t [map->_dm_segcnt - 1]);
+@@ -178,13 +307,17 @@ _bus_dmamap_load_buffer(bus_dma_tag_t t,
+ else
+ curaddr = vtophys(vaddr);
+
++ unsigned long long machaddr =
rumpcomp_pci_virt_to_mach((void*)curaddr);
+ /*
+ * If we're beyond the bounce threshold, notify
+ * the caller.
+ */
++
+ if (map->_dm_bounce_thresh != 0 &&
+- curaddr >= map->_dm_bounce_thresh)
+- return (EINVAL);
++ machaddr >= map->_dm_bounce_thresh)
++ {
++ return (EINVAL);
++ }
+
+ /*
+ * Compute the segment size, and adjust counts.
+@@ -209,7 +342,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t t,
+ */
+ if (first) {
+ map->dm_segs[seg].ds_addr
+- = rumpcomp_pci_virt_to_mach((void *)curaddr);
++ = machaddr;
+ map->dm_segs[seg].ds_len = sgsize;
+ first = 0;
+ } else {
+@@ -218,13 +351,13 @@ _bus_dmamap_load_buffer(bus_dma_tag_t t,
+ map->dm_maxsegsz &&
+ (map->_dm_boundary == 0 ||
+ (map->dm_segs[seg].ds_addr & bmask) ==
+- (rumpcomp_pci_virt_to_mach((void*)curaddr)&bmask)))
++ (machaddr & bmask)))
+ map->dm_segs[seg].ds_len += sgsize;
+ else {
+ if (++seg >= map->_dm_segcnt)
+ break;
+ map->dm_segs[seg].ds_addr =
+- rumpcomp_pci_virt_to_mach((void *)curaddr);
++ machaddr;
+ map->dm_segs[seg].ds_len = sgsize;
+ }
+ }
+@@ -265,6 +398,7 @@ bus_dmamap_load(bus_dma_tag_t t, bus_dma
+ int seg, error;
+ struct vmspace *vm;
+
++ struct rump_bus_dma_cookie *cookie = map->_dm_cookie;
+ /*
+ * Make sure that on error condition we return "no valid mappings".
+ */
+@@ -285,10 +419,47 @@ bus_dmamap_load(bus_dma_tag_t t, bus_dma
+ error = _bus_dmamap_load_buffer(t, map, buf, buflen, vm, flags,
+ &lastaddr, &seg, 1);
+ if (error == 0) {
++ if (cookie != NULL)
++ cookie->id_flags &= ~RUMP_DMA_IS_BOUNCING;
+ map->dm_mapsize = buflen;
+ map->dm_nsegs = seg + 1;
++ return 0;
+ }
+- return (error);
++
++ if (cookie == NULL ||
++ (cookie->id_flags & RUMP_DMA_MIGHT_NEED_BOUNCE) == 0)
++ return error;
++
++ /*
++ * First attempt failed; bounce it.
++ */
++
++ /*
++ * Allocate bounce pages, if necessary.
++ */
++ if ((cookie->id_flags & RUMP_DMA_HAS_BOUNCE) == 0) {
++ error = _bus_dma_alloc_bouncebuf(t, map, buflen, flags);
++ if (error)
++ return (error);
++ }
++
++ /*
++ * Cache a pointer to the caller's buffer and load the DMA map
++ * with the bounce buffer.
++ */
++ cookie->id_origbuf = buf;
++ cookie->id_origbuflen = buflen;
++ cookie->id_buftype = RUMP_DMA_BUFTYPE_LINEAR;
++ map->dm_nsegs = 0;
++
++ error = bus_dmamap_load(t, map, cookie->id_bouncebuf, buflen,
++ p, flags);
++ if (error)
++ return (error);
++
++ /* ...so bus_dmamap_sync() knows we're bouncing */
++ cookie->id_flags |= RUMP_DMA_IS_BOUNCING;
++ return (0);
+ }
+
+ /*
+@@ -298,6 +469,8 @@ int
+ bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map,
+ struct mbuf *m0, int flags)
+ {
++ struct rump_bus_dma_cookie *cookie = map->_dm_cookie;
++
+ bus_addr_t lastaddr = 0;
+ int seg, error, first;
+ struct mbuf *m;
+@@ -358,7 +531,18 @@ bus_dmamap_load_mbuf(bus_dma_tag_t t, bu
+ if (error == 0) {
+ map->dm_mapsize = m0->m_pkthdr.len;
+ map->dm_nsegs = seg + 1;
++ return 0;
+ }
++
++ map->dm_nsegs = 0;
++
++ if (cookie == NULL ||
++ (cookie->id_flags & RUMP_DMA_MIGHT_NEED_BOUNCE) == 0)
++ return error;
++
++ // Not implemented yet - Hurd doesn't use this interface.
++ panic("bus_dmamap_load_mbuf bounce buffers");
++
+ return (error);
+ }
+
+@@ -369,6 +553,8 @@ int
+ bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map,
+ struct uio *uio, int flags)
+ {
++ struct rump_bus_dma_cookie *cookie = map->_dm_cookie;
++
+ bus_addr_t lastaddr = 0;
+ int seg, i, error, first;
+ bus_size_t minlen, resid;
+@@ -405,7 +591,18 @@ bus_dmamap_load_uio(bus_dma_tag_t t, bus
+ if (error == 0) {
+ map->dm_mapsize = uio->uio_resid;
+ map->dm_nsegs = seg + 1;
++ return 0;
+ }
++
++ map->dm_nsegs = 0;
++
++ if (cookie == NULL ||
++ (cookie->id_flags & RUMP_DMA_MIGHT_NEED_BOUNCE) == 0)
++ return error;
++
++ // Not implemented yet - Hurd doesn't use this interface.
++ panic("bus_dmamap_load_uio bounce buffers");
++
+ return (error);
+ }
+
+@@ -428,6 +625,16 @@ bus_dmamap_load_raw(bus_dma_tag_t t, bus
+ void
+ bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
+ {
++ struct rump_bus_dma_cookie *cookie = map->_dm_cookie;
++
++ /*
++ * If we have bounce pages, free them, unless they're
++ * reserved for our exclusive use.
++ */
++ if (cookie != NULL) {
++ cookie->id_flags &= ~RUMP_DMA_IS_BOUNCING;
++ cookie->id_buftype = RUMP_DMA_BUFTYPE_INVALID;
++ }
+
+ /*
+ * No resources to free; just mark the mappings as
+@@ -438,14 +645,137 @@ bus_dmamap_unload(bus_dma_tag_t t, bus_d
+ map->dm_nsegs = 0;
+ }
+
++#if defined(__i386__) || defined(__x86_64__)
++
++#define PRIxBUSADDR "lx"
++#define PRIxBUSSIZE "lx"
++
+ void
+ bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map,
+ bus_addr_t offset, bus_size_t len, int ops)
+ {
++ struct rump_bus_dma_cookie *cookie = map->_dm_cookie;
++
++ /*
++ * Mixing PRE and POST operations is not allowed.
++ */
++ if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 &&
++ (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0)
++ panic("%s: mix PRE and POST", __func__);
++
++ if ((ops & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD)) != 0) {
++ KASSERTMSG(offset < map->dm_mapsize,
++ "bad offset 0x%"PRIxBUSADDR" >= 0x%"PRIxBUSSIZE,
++ offset, map->dm_mapsize);
++ KASSERTMSG(len <= map->dm_mapsize - offset,
++ "bad length 0x%"PRIxBUSADDR" + 0x%"PRIxBUSSIZE
++ " > 0x%"PRIxBUSSIZE,
++ offset, len, map->dm_mapsize);
++ }
++
++ /*
++ * BUS_DMASYNC_POSTREAD: The caller has been alerted to DMA
++ * completion by reading a register or DMA descriptor, and the
++ * caller is about to read out of the DMA memory buffer that
++ * the device just filled.
++ *
++ * => LFENCE ensures that these happen in order so that the
++ * caller, or the bounce buffer logic here, doesn't proceed
++ * to read any stale data from cache or speculation. x86
++ * never reorders loads from wp/wt/wb or uc memory, but it
++ * may execute loads from wc/wc+ memory early, e.g. with
++ * BUS_SPACE_MAP_PREFETCHABLE.
++ */
++ if (ops & BUS_DMASYNC_POSTREAD)
++ x86_lfence();
++
++ /*
++ * If we're not bouncing, just return; nothing to do.
++ */
++ if (len == 0 || cookie == NULL ||
++ (cookie->id_flags & RUMP_DMA_IS_BOUNCING) == 0)
++ goto end;
++
++ switch (cookie->id_buftype) {
++ case RUMP_DMA_BUFTYPE_LINEAR:
++ /*
++ * Nothing to do for pre-read.
++ */
+
+- /* XXX: this might need some MD tweaks */
+- membar_sync();
++ if (ops & BUS_DMASYNC_PREWRITE) {
++ /*
++ * Copy the caller's buffer to the bounce buffer.
++ */
++ memcpy((char *)cookie->id_bouncebuf + offset,
++ (char *)cookie->id_origbuf + offset, len);
++ }
++
++ if (ops & BUS_DMASYNC_POSTREAD) {
++ /*
++ * Copy the bounce buffer to the caller's buffer.
++ */
++ memcpy((char *)cookie->id_origbuf + offset,
++ (char *)cookie->id_bouncebuf + offset, len);
++ }
++
++ /*
++ * Nothing to do for post-write.
++ */
++ break;
++
++ case RUMP_DMA_BUFTYPE_INVALID:
++ panic("%s: RUMP_DMA_BUFTYPE_INVALID", __func__);
++ break;
++ default:
++ panic("%s: unknown buffer type %d", __func__,
++ cookie->id_buftype);
++ break;
++ }
++end:
++ /*
++ * BUS_DMASYNC_PREREAD: The caller may have previously been
++ * using a DMA memory buffer, with loads and stores, and is
++ * about to trigger DMA by writing to a register or DMA
++ * descriptor.
++ *
++ * => SFENCE ensures that the stores happen in order, in case
++ * the latter one is non-temporal or to wc/wc+ memory and
++ * thus may be executed early. x86 never reorders
++ * load;store to store;load for any memory type, so no
++ * barrier is needed for prior loads.
++ *
++ * BUS_DMASYNC_PREWRITE: The caller has just written to a DMA
++ * memory buffer, or we just wrote to to the bounce buffer,
++ * data that the device needs to use, and the caller is about
++ * to trigger DMA by writing to a register or DMA descriptor.
++ *
++ * => SFENCE ensures that these happen in order so that any
++ * buffered stores are visible to the device before the DMA
++ * is triggered. x86 never reorders (non-temporal) stores
++ * to wp/wt/wb or uc memory, but it may reorder two stores
++ * if one is to wc/wc+ memory, e.g. if the DMA descriptor is
++ * mapped with BUS_SPACE_MAP_PREFETCHABLE.
++ */
++ if (ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE))
++ x86_sfence();
++
++ /*
++ * BUS_DMASYNC_POSTWRITE: The caller has been alerted to DMA
++ * completion by reading a register or DMA descriptor, and the
++ * caller may proceed to reuse the DMA memory buffer, with
++ * loads and stores.
++ *
++ * => No barrier is needed. Since the DMA memory buffer is not
++ * changing (we're sending data to the device, not receiving
++ * data from the device), prefetched loads are safe. x86
++ * never reoreders load;store to store;load for any memory
++ * type, so early execution of stores prior to witnessing
++ * the DMA completion is not possible.
++ */
+ }
++#else
++#error "bus_dmamap_sync unsupported"
++#endif
+
+ /*
+ * Common function for freeing DMA-safe memory. May be called by
+Index: rumpkernel/buildrump.sh/src/sys/rump/include/sys/bus.h
+===================================================================
+--- rumpkernel.orig/buildrump.sh/src/sys/rump/include/sys/bus.h
++++ rumpkernel/buildrump.sh/src/sys/rump/include/sys/bus.h
+@@ -41,7 +41,12 @@ typedef unsigned long bus_space_tag_t;
+ typedef unsigned long bus_space_handle_t;
+
+ /* bus dma defs */
+-typedef void *bus_dma_tag_t;
++struct bus_dma_tag {
++ unsigned long long _bounce_thresh;
++};
++
++typedef struct bus_dma_tag *bus_dma_tag_t;
++
+ #define BUS_DMA_TAG_VALID(_tag_) ((_tag_) != NULL)
+
+ typedef struct {
+@@ -56,7 +61,7 @@ typedef struct {
+ int _dm_segcnt;
+ bus_size_t _dm_maxmaxsegsz;
+ bus_size_t _dm_boundary;
+- bus_addr_t _dm_bounce_thresh;
++ unsigned long long _dm_bounce_thresh;
+ int _dm_flags;
+ void *_dm_cookie;
+
+Index:
rumpkernel/buildrump.sh/src/sys/rump/librump/rumpkern/arch/i386/Makefile.inc
+===================================================================
+---
rumpkernel.orig/buildrump.sh/src/sys/rump/librump/rumpkern/arch/i386/Makefile.inc
++++
rumpkernel/buildrump.sh/src/sys/rump/librump/rumpkern/arch/i386/Makefile.inc
+@@ -5,3 +5,5 @@
+
+ .PATH: ${RUMPTOP}/../arch/i386/i386
+ SRCS+= kobj_machdep.c
++
++SRCS+= rump_i386_cpufunc.S
+Index:
rumpkernel/buildrump.sh/src/sys/rump/librump/rumpkern/arch/i386/rump_i386_cpufunc.S
+===================================================================
+--- /dev/null
++++
rumpkernel/buildrump.sh/src/sys/rump/librump/rumpkern/arch/i386/rump_i386_cpufunc.S
+@@ -0,0 +1,19 @@
++#include <machine/asm.h>
++
++ENTRY(x86_lfence)
++ lock
++ addl $0, -4(%esp)
++ ret
++END(x86_lfence)
++
++ENTRY(x86_sfence)
++ lock
++ addl $0, -4(%esp)
++ ret
++END(x86_sfence)
++
++ENTRY(x86_mfence)
++ lock
++ addl $0, -4(%esp)
++ ret
++END(x86_mfence)
+Index:
rumpkernel/buildrump.sh/src/sys/rump/librump/rumpkern/arch/x86_64/Makefile.inc
+===================================================================
+---
rumpkernel.orig/buildrump.sh/src/sys/rump/librump/rumpkern/arch/x86_64/Makefile.inc
++++
rumpkernel/buildrump.sh/src/sys/rump/librump/rumpkern/arch/x86_64/Makefile.inc
+@@ -8,3 +8,5 @@ SRCS+= kobj_machdep.c
+
+ .PATH: ${RUMPTOP}/librump/rumpkern/arch/generic
+ SRCS+= rump_generic_directmap.c
++
++SRCS+= rump_amd64_cpufunc.S
+Index:
rumpkernel/buildrump.sh/src/sys/rump/librump/rumpkern/arch/x86_64/rump_amd64_cpufunc.S
+===================================================================
+--- /dev/null
++++
rumpkernel/buildrump.sh/src/sys/rump/librump/rumpkern/arch/x86_64/rump_amd64_cpufunc.S
+@@ -0,0 +1,16 @@
++#include <machine/asm.h>
++
++ENTRY(x86_lfence)
++ lfence
++ ret
++END(x86_lfence)
++
++ENTRY(x86_sfence)
++ sfence
++ ret
++END(x86_sfence)
++
++ENTRY(x86_mfence)
++ mfence
++ ret
++END(x86_mfence)
diff --git a/debian/patches/series b/debian/patches/series
index 1ed589441..128f51a50 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -31,3 +31,4 @@ rump_bus_dma
hci_shared_intr
nonstring
rumpuser-mem.diff
+dma_bounce_buffers.diff
--
2.53.0