| PARAVIRT_MEMBAR_SYNC(9) | Kernel Developer's Manual | PARAVIRT_MEMBAR_SYNC(9) |
paravirt_membar_sync —
memory 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 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.
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.
These atomic operations first appeared in NetBSD 12.0.
| August 31, 2025 | NetBSD 11.0 |