PARAVIRT_MEMBAR_SYNC(9)

NAME
paravirt_membar_sync - memory barrier for paravirtualized device drivers

SYNOPSIS
#include <sys/paravirt_membar.h>
void
paravirt_membar_sync(void);

DESCRIPTION
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 virtual 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 physical CPU requiring a barrier that membar_sync(3) does not issue.

EXAMPLES
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;

N.B.: Other ordering or bouncing may be required with bus_dmamap_sync(9); this is independent of paravirt_membar_sync, which is needed in addition to 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.

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

HISTORY
These atomic operations first appeared in NetBSD 12.0.