diff options
author | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2017-02-08 16:15:53 +0000 |
---|---|---|
committer | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2017-02-08 16:15:53 +0000 |
commit | 831d3b3ec9b67afc77d3f6d1a829e501cc02322d (patch) | |
tree | 0912b5ba218915bd14fefc9eef130b151127de6a /sys/dev | |
parent | a4d04d4c3b95eb335f51ce7f72b13190bd46c4a2 (diff) |
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')
-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); |