summaryrefslogtreecommitdiffstats
path: root/sys/dev/pv/xen.c
diff options
context:
space:
mode:
authormikeb <mikeb@openbsd.org>2017-02-08 16:15:52 +0000
committermikeb <mikeb@openbsd.org>2017-02-08 16:15:52 +0000
commit6123be6232257013ab87846bf4b9b4e7311318fd (patch)
tree05e0681f769450215f6306135b42aad74c891502 /sys/dev/pv/xen.c
parentFixup incorrect test when allocating grant table entries (diff)
downloadwireguard-openbsd-6123be6232257013ab87846bf4b9b4e7311318fd.tar.xz
wireguard-openbsd-6123be6232257013ab87846bf4b9b4e7311318fd.zip
Introduce Xen interrupt barriers
intr_barrier(9) is useful to make sure that after an interrupt is masked, the interrupt handler for the device has finished executing before proceeding with further device configuration. However, since Xen interrupt handlers run in the thread context, we need to make sure that they have finished as well. By scheduling a xen_barrier_task modelled after (or rather copied ;) ifq_barrier_task we can ensure that the interrupt handler is no longer running.
Diffstat (limited to 'sys/dev/pv/xen.c')
-rw-r--r--sys/dev/pv/xen.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/sys/dev/pv/xen.c b/sys/dev/pv/xen.c
index 1e93de05e83..3ceda5540a7 100644
--- a/sys/dev/pv/xen.c
+++ b/sys/dev/pv/xen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: xen.c,v 1.77 2017/02/08 16:08:06 mikeb Exp $ */
+/* $OpenBSD: xen.c,v 1.78 2017/02/08 16:15:52 mikeb Exp $ */
/*
* Copyright (c) 2015 Mike Belopuhov
@@ -696,6 +696,49 @@ xen_intr_schedule(xen_intr_handle_t xih)
}
}
+static void
+xen_barrier_task(void *arg)
+{
+ int *notdone = arg;
+
+ *notdone = 0;
+ wakeup_one(notdone);
+}
+
+/*
+ * This code achieves two goals: 1) makes sure that *after* masking
+ * the interrupt source we're not getting more task_adds: intr_barrier
+ * will take care of that, and 2) makes sure that the interrupt task
+ * is finished executing the current task and won't be called again:
+ * it sets up a barrier task to await completion of the current task
+ * and relies on the interrupt masking to prevent submission of new
+ * tasks in the future.
+ */
+void
+xen_intr_barrier(xen_intr_handle_t xih)
+{
+ struct xen_softc *sc = xen_sc;
+ struct xen_intsrc *xi;
+ struct sleep_state sls;
+ int notdone = 1;
+ struct task t = TASK_INITIALIZER(xen_barrier_task, &notdone);
+
+ /*
+ * XXX This will need to be revised once intr_barrier starts
+ * using an argument.
+ */
+ intr_barrier(NULL);
+
+ if ((xi = xen_intsrc_acquire(sc, (evtchn_port_t)xih)) != NULL) {
+ task_add(xi->xi_taskq, &t);
+ while (notdone) {
+ sleep_setup(&sls, &notdone, PWAIT, "xenbar");
+ sleep_finish(&sls, notdone);
+ }
+ xen_intsrc_release(sc, xi);
+ }
+}
+
void
xen_intr_signal(xen_intr_handle_t xih)
{