diff options
-rw-r--r-- | sys/dev/pv/xen.c | 45 | ||||
-rw-r--r-- | sys/dev/pv/xenvar.h | 3 |
2 files changed, 46 insertions, 2 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, ¬done); + + /* + * 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, ¬done, PWAIT, "xenbar"); + sleep_finish(&sls, notdone); + } + xen_intsrc_release(sc, xi); + } +} + void xen_intr_signal(xen_intr_handle_t xih) { diff --git a/sys/dev/pv/xenvar.h b/sys/dev/pv/xenvar.h index 48c0a6b3d46..61a4dcb920b 100644 --- a/sys/dev/pv/xenvar.h +++ b/sys/dev/pv/xenvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: xenvar.h,v 1.48 2017/02/06 21:58:29 mikeb Exp $ */ +/* $OpenBSD: xenvar.h,v 1.49 2017/02/08 16:15:52 mikeb Exp $ */ /* * Copyright (c) 2015 Mike Belopuhov @@ -144,6 +144,7 @@ void xen_intr(void); void xen_intr_ack(void); void xen_intr_signal(xen_intr_handle_t); void xen_intr_schedule(xen_intr_handle_t); +void xen_intr_barrier(xen_intr_handle_t); int xen_intr_establish(evtchn_port_t, xen_intr_handle_t *, int, void (*)(void *), void *, char *); int xen_intr_disestablish(xen_intr_handle_t); |