Updated: 2025/Nov/16

Please read Privacy Policy. It's for your privacy.


PARAVIRT_MEMBAR_SYNC(9)    Kernel Developer's Manual   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.

NetBSD 11.99                    August 31, 2025                   NetBSD 11.99