PARAVIRT_MEMBAR_SYNC(9) Kernel Developer's Manual PARAVIRT_MEMBAR_SYNC(9)

paravirt_membar_syncmemory barrier for paravirtualized device drivers

#include <sys/paravirt_membar.h>

void
paravirt_membar_sync(void);

The paravirt_membar_sync function issues a store-before-load barrier for coordination with a paravirtualized device.

This function has the same ordering semantics as membar_sync(3), but membar_sync(3) can only coordinate with other CPUs that NetBSD is running on. In a virtual machine, NetBSD may be running on a single CPU, and patch membar_sync(3) to be a no-op, while the host side of a paravirtualized device may be running on a different CPU requiring a barrier that membar_sync(3) does not issue.

Submit a request to the host device, and notify the host to process it—but elide the notification, which is expensive, if the host is already reading requests anyway:

	/*
	 * Write the request into the ring buffer.
	 */
	memcpy(cputodev_ring->buffer[sc->sc_cputodev_idx], request,
	    sizeof(*request));

	/*
	 * Publish the request to the host device side.
	 */
	cputodev_ring->header->producer_tail = ++sc->sc_cputodev_idx;

	/*
	 * Ensure we have published it _before_ we check whether the
	 * host needs notification.
	 */
	paravirt_membar_sync();

	/*
	 * Notify the host, if needed.  Notifying the host is usually
	 * expensive (trap to hypervisor), so we try to avoid it if not
	 * needed.
	 */
	if (cputodev_ring->header->needs_notification)
		notify_host();

Enable interrupts from the host and check whether any were pending while interrupts were disabled:

	/*
	 * Tell the host device to deliver interrupts after this
	 * point.
	 */
restart:
	devtocpu_ring->header->needs_notification = true;

	/*
	 * Ensure we have requested interrupts _before_ we check
	 * whether we missed any notifications.
	 */
	paravirt_membar_sync();

	/*
	 * Check whether there were any pending notifications while
	 * interrupts were blocked.  If not, stop here.
	 */
	idx = devtocpu_ring->header->producer_idx;
	if (sc->sc_devtocpu_idx == idx)
		return;

	/*
	 * Process the notifications.
	 */
	devtocpu_ring->header->needs_notification = false;
	while (sc->sc_devtocpu_idx != idx) {
		struct buffer *buf =
		    devtocpu_ring->buffer[sc->sc_devtocpu_idx];
		process_notification(buf);
		sc->sc_devtocpu_idx++;
		sc->sc_devtocpu_idx %= ringlen;
	}
	goto restart;

Other ordering or bouncing may be required with bus_dmamap_sync(9); this is independent of paravirt_membar_sync, which is needed bus_dmamap_sync(9) to guarantee store-before-load ordering when there is no intervening I/O doorbell trigger for a DMA operation, nor interrupt delivery for a DMA completion.

membar_ops(3), bus_dma(9), bus_space(9)

These atomic operations first appeared in NetBSD 12.0.

August 31, 2025 NetBSD 11.0